##// END OF EJS Templates
Fixed that Project.uniq.visible errors under certain conditions (#21182)....
Jean-Philippe Lang -
r14475:151892c3131a
parent child
Show More
@@ -1,185 +1,184
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2015 Jean-Philippe Lang
2 # Copyright (C) 2006-2015 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 class Principal < ActiveRecord::Base
18 class Principal < ActiveRecord::Base
19 self.table_name = "#{table_name_prefix}users#{table_name_suffix}"
19 self.table_name = "#{table_name_prefix}users#{table_name_suffix}"
20
20
21 # Account statuses
21 # Account statuses
22 STATUS_ANONYMOUS = 0
22 STATUS_ANONYMOUS = 0
23 STATUS_ACTIVE = 1
23 STATUS_ACTIVE = 1
24 STATUS_REGISTERED = 2
24 STATUS_REGISTERED = 2
25 STATUS_LOCKED = 3
25 STATUS_LOCKED = 3
26
26
27 has_many :members, :foreign_key => 'user_id', :dependent => :destroy
27 has_many :members, :foreign_key => 'user_id', :dependent => :destroy
28 has_many :memberships,
28 has_many :memberships,
29 lambda {preload(:project, :roles).
29 lambda {preload(:project, :roles).
30 joins(:project).
30 joins(:project).
31 where("#{Project.table_name}.status<>#{Project::STATUS_ARCHIVED}").
31 where("#{Project.table_name}.status<>#{Project::STATUS_ARCHIVED}")},
32 order("#{Project.table_name}.name")},
33 :class_name => 'Member',
32 :class_name => 'Member',
34 :foreign_key => 'user_id'
33 :foreign_key => 'user_id'
35 has_many :projects, :through => :memberships
34 has_many :projects, :through => :memberships
36 has_many :issue_categories, :foreign_key => 'assigned_to_id', :dependent => :nullify
35 has_many :issue_categories, :foreign_key => 'assigned_to_id', :dependent => :nullify
37
36
38 # Groups and active users
37 # Groups and active users
39 scope :active, lambda { where(:status => STATUS_ACTIVE) }
38 scope :active, lambda { where(:status => STATUS_ACTIVE) }
40
39
41 scope :visible, lambda {|*args|
40 scope :visible, lambda {|*args|
42 user = args.first || User.current
41 user = args.first || User.current
43
42
44 if user.admin?
43 if user.admin?
45 all
44 all
46 else
45 else
47 view_all_active = false
46 view_all_active = false
48 if user.memberships.to_a.any?
47 if user.memberships.to_a.any?
49 view_all_active = user.memberships.any? {|m| m.roles.any? {|r| r.users_visibility == 'all'}}
48 view_all_active = user.memberships.any? {|m| m.roles.any? {|r| r.users_visibility == 'all'}}
50 else
49 else
51 view_all_active = user.builtin_role.users_visibility == 'all'
50 view_all_active = user.builtin_role.users_visibility == 'all'
52 end
51 end
53
52
54 if view_all_active
53 if view_all_active
55 active
54 active
56 else
55 else
57 # self and members of visible projects
56 # self and members of visible projects
58 active.where("#{table_name}.id = ? OR #{table_name}.id IN (SELECT user_id FROM #{Member.table_name} WHERE project_id IN (?))",
57 active.where("#{table_name}.id = ? OR #{table_name}.id IN (SELECT user_id FROM #{Member.table_name} WHERE project_id IN (?))",
59 user.id, user.visible_project_ids
58 user.id, user.visible_project_ids
60 )
59 )
61 end
60 end
62 end
61 end
63 }
62 }
64
63
65 scope :like, lambda {|q|
64 scope :like, lambda {|q|
66 q = q.to_s
65 q = q.to_s
67 if q.blank?
66 if q.blank?
68 where({})
67 where({})
69 else
68 else
70 pattern = "%#{q}%"
69 pattern = "%#{q}%"
71 sql = %w(login firstname lastname).map {|column| "LOWER(#{table_name}.#{column}) LIKE LOWER(:p)"}.join(" OR ")
70 sql = %w(login firstname lastname).map {|column| "LOWER(#{table_name}.#{column}) LIKE LOWER(:p)"}.join(" OR ")
72 sql << " OR #{table_name}.id IN (SELECT user_id FROM #{EmailAddress.table_name} WHERE LOWER(address) LIKE LOWER(:p))"
71 sql << " OR #{table_name}.id IN (SELECT user_id FROM #{EmailAddress.table_name} WHERE LOWER(address) LIKE LOWER(:p))"
73 params = {:p => pattern}
72 params = {:p => pattern}
74 if q =~ /^(.+)\s+(.+)$/
73 if q =~ /^(.+)\s+(.+)$/
75 a, b = "#{$1}%", "#{$2}%"
74 a, b = "#{$1}%", "#{$2}%"
76 sql << " OR (LOWER(#{table_name}.firstname) LIKE LOWER(:a) AND LOWER(#{table_name}.lastname) LIKE LOWER(:b))"
75 sql << " OR (LOWER(#{table_name}.firstname) LIKE LOWER(:a) AND LOWER(#{table_name}.lastname) LIKE LOWER(:b))"
77 sql << " OR (LOWER(#{table_name}.firstname) LIKE LOWER(:b) AND LOWER(#{table_name}.lastname) LIKE LOWER(:a))"
76 sql << " OR (LOWER(#{table_name}.firstname) LIKE LOWER(:b) AND LOWER(#{table_name}.lastname) LIKE LOWER(:a))"
78 params.merge!(:a => a, :b => b)
77 params.merge!(:a => a, :b => b)
79 end
78 end
80 where(sql, params)
79 where(sql, params)
81 end
80 end
82 }
81 }
83
82
84 # Principals that are members of a collection of projects
83 # Principals that are members of a collection of projects
85 scope :member_of, lambda {|projects|
84 scope :member_of, lambda {|projects|
86 projects = [projects] if projects.is_a?(Project)
85 projects = [projects] if projects.is_a?(Project)
87 if projects.blank?
86 if projects.blank?
88 where("1=0")
87 where("1=0")
89 else
88 else
90 ids = projects.map(&:id)
89 ids = projects.map(&:id)
91 active.where("#{Principal.table_name}.id IN (SELECT DISTINCT user_id FROM #{Member.table_name} WHERE project_id IN (?))", ids)
90 active.where("#{Principal.table_name}.id IN (SELECT DISTINCT user_id FROM #{Member.table_name} WHERE project_id IN (?))", ids)
92 end
91 end
93 }
92 }
94 # Principals that are not members of projects
93 # Principals that are not members of projects
95 scope :not_member_of, lambda {|projects|
94 scope :not_member_of, lambda {|projects|
96 projects = [projects] unless projects.is_a?(Array)
95 projects = [projects] unless projects.is_a?(Array)
97 if projects.empty?
96 if projects.empty?
98 where("1=0")
97 where("1=0")
99 else
98 else
100 ids = projects.map(&:id)
99 ids = projects.map(&:id)
101 where("#{Principal.table_name}.id NOT IN (SELECT DISTINCT user_id FROM #{Member.table_name} WHERE project_id IN (?))", ids)
100 where("#{Principal.table_name}.id NOT IN (SELECT DISTINCT user_id FROM #{Member.table_name} WHERE project_id IN (?))", ids)
102 end
101 end
103 }
102 }
104 scope :sorted, lambda { order(*Principal.fields_for_order_statement)}
103 scope :sorted, lambda { order(*Principal.fields_for_order_statement)}
105
104
106 before_create :set_default_empty_values
105 before_create :set_default_empty_values
107
106
108 def name(formatter = nil)
107 def name(formatter = nil)
109 to_s
108 to_s
110 end
109 end
111
110
112 def mail=(*args)
111 def mail=(*args)
113 nil
112 nil
114 end
113 end
115
114
116 def mail
115 def mail
117 nil
116 nil
118 end
117 end
119
118
120 def visible?(user=User.current)
119 def visible?(user=User.current)
121 Principal.visible(user).where(:id => id).first == self
120 Principal.visible(user).where(:id => id).first == self
122 end
121 end
123
122
124 # Return true if the principal is a member of project
123 # Return true if the principal is a member of project
125 def member_of?(project)
124 def member_of?(project)
126 projects.to_a.include?(project)
125 projects.to_a.include?(project)
127 end
126 end
128
127
129 def <=>(principal)
128 def <=>(principal)
130 if principal.nil?
129 if principal.nil?
131 -1
130 -1
132 elsif self.class.name == principal.class.name
131 elsif self.class.name == principal.class.name
133 self.to_s.casecmp(principal.to_s)
132 self.to_s.casecmp(principal.to_s)
134 else
133 else
135 # groups after users
134 # groups after users
136 principal.class.name <=> self.class.name
135 principal.class.name <=> self.class.name
137 end
136 end
138 end
137 end
139
138
140 # Returns an array of fields names than can be used to make an order statement for principals.
139 # Returns an array of fields names than can be used to make an order statement for principals.
141 # Users are sorted before Groups.
140 # Users are sorted before Groups.
142 # Examples:
141 # Examples:
143 def self.fields_for_order_statement(table=nil)
142 def self.fields_for_order_statement(table=nil)
144 table ||= table_name
143 table ||= table_name
145 columns = ['type DESC'] + (User.name_formatter[:order] - ['id']) + ['lastname', 'id']
144 columns = ['type DESC'] + (User.name_formatter[:order] - ['id']) + ['lastname', 'id']
146 columns.uniq.map {|field| "#{table}.#{field}"}
145 columns.uniq.map {|field| "#{table}.#{field}"}
147 end
146 end
148
147
149 # Returns the principal that matches the keyword among principals
148 # Returns the principal that matches the keyword among principals
150 def self.detect_by_keyword(principals, keyword)
149 def self.detect_by_keyword(principals, keyword)
151 keyword = keyword.to_s
150 keyword = keyword.to_s
152 return nil if keyword.blank?
151 return nil if keyword.blank?
153
152
154 principal = nil
153 principal = nil
155 principal ||= principals.detect {|a| keyword.casecmp(a.login.to_s) == 0}
154 principal ||= principals.detect {|a| keyword.casecmp(a.login.to_s) == 0}
156 principal ||= principals.detect {|a| keyword.casecmp(a.mail.to_s) == 0}
155 principal ||= principals.detect {|a| keyword.casecmp(a.mail.to_s) == 0}
157
156
158 if principal.nil? && keyword.match(/ /)
157 if principal.nil? && keyword.match(/ /)
159 firstname, lastname = *(keyword.split) # "First Last Throwaway"
158 firstname, lastname = *(keyword.split) # "First Last Throwaway"
160 principal ||= principals.detect {|a|
159 principal ||= principals.detect {|a|
161 a.is_a?(User) &&
160 a.is_a?(User) &&
162 firstname.casecmp(a.firstname.to_s) == 0 &&
161 firstname.casecmp(a.firstname.to_s) == 0 &&
163 lastname.casecmp(a.lastname.to_s) == 0
162 lastname.casecmp(a.lastname.to_s) == 0
164 }
163 }
165 end
164 end
166 if principal.nil?
165 if principal.nil?
167 principal ||= principals.detect {|a| keyword.casecmp(a.name) == 0}
166 principal ||= principals.detect {|a| keyword.casecmp(a.name) == 0}
168 end
167 end
169 principal
168 principal
170 end
169 end
171
170
172 protected
171 protected
173
172
174 # Make sure we don't try to insert NULL values (see #4632)
173 # Make sure we don't try to insert NULL values (see #4632)
175 def set_default_empty_values
174 def set_default_empty_values
176 self.login ||= ''
175 self.login ||= ''
177 self.hashed_password ||= ''
176 self.hashed_password ||= ''
178 self.firstname ||= ''
177 self.firstname ||= ''
179 self.lastname ||= ''
178 self.lastname ||= ''
180 true
179 true
181 end
180 end
182 end
181 end
183
182
184 require_dependency "user"
183 require_dependency "user"
185 require_dependency "group"
184 require_dependency "group"
@@ -1,994 +1,1003
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2015 Jean-Philippe Lang
2 # Copyright (C) 2006-2015 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require File.expand_path('../../test_helper', __FILE__)
18 require File.expand_path('../../test_helper', __FILE__)
19
19
20 class ProjectTest < ActiveSupport::TestCase
20 class ProjectTest < ActiveSupport::TestCase
21 fixtures :projects, :trackers, :issue_statuses, :issues,
21 fixtures :projects, :trackers, :issue_statuses, :issues,
22 :journals, :journal_details,
22 :journals, :journal_details,
23 :enumerations, :users, :issue_categories,
23 :enumerations, :users, :issue_categories,
24 :projects_trackers,
24 :projects_trackers,
25 :custom_fields,
25 :custom_fields,
26 :custom_fields_projects,
26 :custom_fields_projects,
27 :custom_fields_trackers,
27 :custom_fields_trackers,
28 :custom_values,
28 :custom_values,
29 :roles,
29 :roles,
30 :member_roles,
30 :member_roles,
31 :members,
31 :members,
32 :enabled_modules,
32 :enabled_modules,
33 :versions,
33 :versions,
34 :wikis, :wiki_pages, :wiki_contents, :wiki_content_versions,
34 :wikis, :wiki_pages, :wiki_contents, :wiki_content_versions,
35 :groups_users,
35 :groups_users,
36 :boards, :messages,
36 :boards, :messages,
37 :repositories,
37 :repositories,
38 :news, :comments,
38 :news, :comments,
39 :documents,
39 :documents,
40 :workflows
40 :workflows
41
41
42 def setup
42 def setup
43 @ecookbook = Project.find(1)
43 @ecookbook = Project.find(1)
44 @ecookbook_sub1 = Project.find(3)
44 @ecookbook_sub1 = Project.find(3)
45 set_tmp_attachments_directory
45 set_tmp_attachments_directory
46 User.current = nil
46 User.current = nil
47 end
47 end
48
48
49 def test_truth
49 def test_truth
50 assert_kind_of Project, @ecookbook
50 assert_kind_of Project, @ecookbook
51 assert_equal "eCookbook", @ecookbook.name
51 assert_equal "eCookbook", @ecookbook.name
52 end
52 end
53
53
54 def test_default_attributes
54 def test_default_attributes
55 with_settings :default_projects_public => '1' do
55 with_settings :default_projects_public => '1' do
56 assert_equal true, Project.new.is_public
56 assert_equal true, Project.new.is_public
57 assert_equal false, Project.new(:is_public => false).is_public
57 assert_equal false, Project.new(:is_public => false).is_public
58 end
58 end
59
59
60 with_settings :default_projects_public => '0' do
60 with_settings :default_projects_public => '0' do
61 assert_equal false, Project.new.is_public
61 assert_equal false, Project.new.is_public
62 assert_equal true, Project.new(:is_public => true).is_public
62 assert_equal true, Project.new(:is_public => true).is_public
63 end
63 end
64
64
65 with_settings :sequential_project_identifiers => '1' do
65 with_settings :sequential_project_identifiers => '1' do
66 assert !Project.new.identifier.blank?
66 assert !Project.new.identifier.blank?
67 assert Project.new(:identifier => '').identifier.blank?
67 assert Project.new(:identifier => '').identifier.blank?
68 end
68 end
69
69
70 with_settings :sequential_project_identifiers => '0' do
70 with_settings :sequential_project_identifiers => '0' do
71 assert Project.new.identifier.blank?
71 assert Project.new.identifier.blank?
72 assert !Project.new(:identifier => 'test').blank?
72 assert !Project.new(:identifier => 'test').blank?
73 end
73 end
74
74
75 with_settings :default_projects_modules => ['issue_tracking', 'repository'] do
75 with_settings :default_projects_modules => ['issue_tracking', 'repository'] do
76 assert_equal ['issue_tracking', 'repository'], Project.new.enabled_module_names
76 assert_equal ['issue_tracking', 'repository'], Project.new.enabled_module_names
77 end
77 end
78 end
78 end
79
79
80 def test_default_trackers_should_match_default_tracker_ids_setting
80 def test_default_trackers_should_match_default_tracker_ids_setting
81 with_settings :default_projects_tracker_ids => ['1', '3'] do
81 with_settings :default_projects_tracker_ids => ['1', '3'] do
82 assert_equal Tracker.find(1, 3).sort, Project.new.trackers.sort
82 assert_equal Tracker.find(1, 3).sort, Project.new.trackers.sort
83 end
83 end
84 end
84 end
85
85
86 def test_default_trackers_should_be_all_trackers_with_blank_setting
86 def test_default_trackers_should_be_all_trackers_with_blank_setting
87 with_settings :default_projects_tracker_ids => nil do
87 with_settings :default_projects_tracker_ids => nil do
88 assert_equal Tracker.all.sort, Project.new.trackers.sort
88 assert_equal Tracker.all.sort, Project.new.trackers.sort
89 end
89 end
90 end
90 end
91
91
92 def test_default_trackers_should_be_empty_with_empty_setting
92 def test_default_trackers_should_be_empty_with_empty_setting
93 with_settings :default_projects_tracker_ids => [] do
93 with_settings :default_projects_tracker_ids => [] do
94 assert_equal [], Project.new.trackers
94 assert_equal [], Project.new.trackers
95 end
95 end
96 end
96 end
97
97
98 def test_default_trackers_should_not_replace_initialized_trackers
98 def test_default_trackers_should_not_replace_initialized_trackers
99 with_settings :default_projects_tracker_ids => ['1', '3'] do
99 with_settings :default_projects_tracker_ids => ['1', '3'] do
100 assert_equal Tracker.find(1, 2).sort, Project.new(:tracker_ids => [1, 2]).trackers.sort
100 assert_equal Tracker.find(1, 2).sort, Project.new(:tracker_ids => [1, 2]).trackers.sort
101 end
101 end
102 end
102 end
103
103
104 def test_update
104 def test_update
105 assert_equal "eCookbook", @ecookbook.name
105 assert_equal "eCookbook", @ecookbook.name
106 @ecookbook.name = "eCook"
106 @ecookbook.name = "eCook"
107 assert @ecookbook.save, @ecookbook.errors.full_messages.join("; ")
107 assert @ecookbook.save, @ecookbook.errors.full_messages.join("; ")
108 @ecookbook.reload
108 @ecookbook.reload
109 assert_equal "eCook", @ecookbook.name
109 assert_equal "eCook", @ecookbook.name
110 end
110 end
111
111
112 def test_validate_identifier
112 def test_validate_identifier
113 to_test = {"abc" => true,
113 to_test = {"abc" => true,
114 "ab12" => true,
114 "ab12" => true,
115 "ab-12" => true,
115 "ab-12" => true,
116 "ab_12" => true,
116 "ab_12" => true,
117 "12" => false,
117 "12" => false,
118 "new" => false}
118 "new" => false}
119
119
120 to_test.each do |identifier, valid|
120 to_test.each do |identifier, valid|
121 p = Project.new
121 p = Project.new
122 p.identifier = identifier
122 p.identifier = identifier
123 p.valid?
123 p.valid?
124 if valid
124 if valid
125 assert p.errors['identifier'].blank?, "identifier #{identifier} was not valid"
125 assert p.errors['identifier'].blank?, "identifier #{identifier} was not valid"
126 else
126 else
127 assert p.errors['identifier'].present?, "identifier #{identifier} was valid"
127 assert p.errors['identifier'].present?, "identifier #{identifier} was valid"
128 end
128 end
129 end
129 end
130 end
130 end
131
131
132 def test_identifier_should_not_be_frozen_for_a_new_project
132 def test_identifier_should_not_be_frozen_for_a_new_project
133 assert_equal false, Project.new.identifier_frozen?
133 assert_equal false, Project.new.identifier_frozen?
134 end
134 end
135
135
136 def test_identifier_should_not_be_frozen_for_a_saved_project_with_blank_identifier
136 def test_identifier_should_not_be_frozen_for_a_saved_project_with_blank_identifier
137 Project.where(:id => 1).update_all(["identifier = ''"])
137 Project.where(:id => 1).update_all(["identifier = ''"])
138 assert_equal false, Project.find(1).identifier_frozen?
138 assert_equal false, Project.find(1).identifier_frozen?
139 end
139 end
140
140
141 def test_identifier_should_be_frozen_for_a_saved_project_with_valid_identifier
141 def test_identifier_should_be_frozen_for_a_saved_project_with_valid_identifier
142 assert_equal true, Project.find(1).identifier_frozen?
142 assert_equal true, Project.find(1).identifier_frozen?
143 end
143 end
144
144
145 def test_to_param_should_be_nil_for_new_records
145 def test_to_param_should_be_nil_for_new_records
146 project = Project.new
146 project = Project.new
147 project.identifier = "foo"
147 project.identifier = "foo"
148 assert_nil project.to_param
148 assert_nil project.to_param
149 end
149 end
150
150
151 def test_members_should_be_active_users
151 def test_members_should_be_active_users
152 Project.all.each do |project|
152 Project.all.each do |project|
153 assert_nil project.members.detect {|m| !(m.user.is_a?(User) && m.user.active?) }
153 assert_nil project.members.detect {|m| !(m.user.is_a?(User) && m.user.active?) }
154 end
154 end
155 end
155 end
156
156
157 def test_users_should_be_active_users
157 def test_users_should_be_active_users
158 Project.all.each do |project|
158 Project.all.each do |project|
159 assert_nil project.users.detect {|u| !(u.is_a?(User) && u.active?) }
159 assert_nil project.users.detect {|u| !(u.is_a?(User) && u.active?) }
160 end
160 end
161 end
161 end
162
162
163 def test_open_scope_on_issues_association
163 def test_open_scope_on_issues_association
164 assert_kind_of Issue, Project.find(1).issues.open.first
164 assert_kind_of Issue, Project.find(1).issues.open.first
165 end
165 end
166
166
167 def test_archive
167 def test_archive
168 user = @ecookbook.members.first.user
168 user = @ecookbook.members.first.user
169 @ecookbook.archive
169 @ecookbook.archive
170 @ecookbook.reload
170 @ecookbook.reload
171
171
172 assert !@ecookbook.active?
172 assert !@ecookbook.active?
173 assert @ecookbook.archived?
173 assert @ecookbook.archived?
174 assert !user.projects.include?(@ecookbook)
174 assert !user.projects.include?(@ecookbook)
175 # Subproject are also archived
175 # Subproject are also archived
176 assert !@ecookbook.children.empty?
176 assert !@ecookbook.children.empty?
177 assert @ecookbook.descendants.active.empty?
177 assert @ecookbook.descendants.active.empty?
178 end
178 end
179
179
180 def test_archive_should_fail_if_versions_are_used_by_non_descendant_projects
180 def test_archive_should_fail_if_versions_are_used_by_non_descendant_projects
181 # Assign an issue of a project to a version of a child project
181 # Assign an issue of a project to a version of a child project
182 Issue.find(4).update_attribute :fixed_version_id, 4
182 Issue.find(4).update_attribute :fixed_version_id, 4
183
183
184 assert_no_difference "Project.where(:status => Project::STATUS_ARCHIVED).count" do
184 assert_no_difference "Project.where(:status => Project::STATUS_ARCHIVED).count" do
185 assert_equal false, @ecookbook.archive
185 assert_equal false, @ecookbook.archive
186 end
186 end
187 @ecookbook.reload
187 @ecookbook.reload
188 assert @ecookbook.active?
188 assert @ecookbook.active?
189 end
189 end
190
190
191 def test_unarchive
191 def test_unarchive
192 user = @ecookbook.members.first.user
192 user = @ecookbook.members.first.user
193 @ecookbook.archive
193 @ecookbook.archive
194 # A subproject of an archived project can not be unarchived
194 # A subproject of an archived project can not be unarchived
195 assert !@ecookbook_sub1.unarchive
195 assert !@ecookbook_sub1.unarchive
196
196
197 # Unarchive project
197 # Unarchive project
198 assert @ecookbook.unarchive
198 assert @ecookbook.unarchive
199 @ecookbook.reload
199 @ecookbook.reload
200 assert @ecookbook.active?
200 assert @ecookbook.active?
201 assert !@ecookbook.archived?
201 assert !@ecookbook.archived?
202 assert user.projects.include?(@ecookbook)
202 assert user.projects.include?(@ecookbook)
203 # Subproject can now be unarchived
203 # Subproject can now be unarchived
204 @ecookbook_sub1.reload
204 @ecookbook_sub1.reload
205 assert @ecookbook_sub1.unarchive
205 assert @ecookbook_sub1.unarchive
206 end
206 end
207
207
208 def test_destroy
208 def test_destroy
209 # 2 active members
209 # 2 active members
210 assert_equal 2, @ecookbook.members.size
210 assert_equal 2, @ecookbook.members.size
211 # and 1 is locked
211 # and 1 is locked
212 assert_equal 3, Member.where(:project_id => @ecookbook.id).count
212 assert_equal 3, Member.where(:project_id => @ecookbook.id).count
213 # some boards
213 # some boards
214 assert @ecookbook.boards.any?
214 assert @ecookbook.boards.any?
215
215
216 @ecookbook.destroy
216 @ecookbook.destroy
217 # make sure that the project non longer exists
217 # make sure that the project non longer exists
218 assert_raise(ActiveRecord::RecordNotFound) { Project.find(@ecookbook.id) }
218 assert_raise(ActiveRecord::RecordNotFound) { Project.find(@ecookbook.id) }
219 # make sure related data was removed
219 # make sure related data was removed
220 assert_nil Member.where(:project_id => @ecookbook.id).first
220 assert_nil Member.where(:project_id => @ecookbook.id).first
221 assert_nil Board.where(:project_id => @ecookbook.id).first
221 assert_nil Board.where(:project_id => @ecookbook.id).first
222 assert_nil Issue.where(:project_id => @ecookbook.id).first
222 assert_nil Issue.where(:project_id => @ecookbook.id).first
223 end
223 end
224
224
225 def test_destroy_should_destroy_subtasks
225 def test_destroy_should_destroy_subtasks
226 issues = (0..2).to_a.map {Issue.create!(:project_id => 1, :tracker_id => 1, :author_id => 1, :subject => 'test')}
226 issues = (0..2).to_a.map {Issue.create!(:project_id => 1, :tracker_id => 1, :author_id => 1, :subject => 'test')}
227 issues[0].update_attribute :parent_issue_id, issues[1].id
227 issues[0].update_attribute :parent_issue_id, issues[1].id
228 issues[2].update_attribute :parent_issue_id, issues[1].id
228 issues[2].update_attribute :parent_issue_id, issues[1].id
229 assert_equal 2, issues[1].children.count
229 assert_equal 2, issues[1].children.count
230
230
231 assert_nothing_raised do
231 assert_nothing_raised do
232 Project.find(1).destroy
232 Project.find(1).destroy
233 end
233 end
234 assert_equal 0, Issue.where(:id => issues.map(&:id)).count
234 assert_equal 0, Issue.where(:id => issues.map(&:id)).count
235 end
235 end
236
236
237 def test_destroying_root_projects_should_clear_data
237 def test_destroying_root_projects_should_clear_data
238 Project.roots.each do |root|
238 Project.roots.each do |root|
239 root.destroy
239 root.destroy
240 end
240 end
241
241
242 assert_equal 0, Project.count, "Projects were not deleted: #{Project.all.inspect}"
242 assert_equal 0, Project.count, "Projects were not deleted: #{Project.all.inspect}"
243 assert_equal 0, Member.count, "Members were not deleted: #{Member.all.inspect}"
243 assert_equal 0, Member.count, "Members were not deleted: #{Member.all.inspect}"
244 assert_equal 0, MemberRole.count
244 assert_equal 0, MemberRole.count
245 assert_equal 0, Issue.count
245 assert_equal 0, Issue.count
246 assert_equal 0, Journal.count
246 assert_equal 0, Journal.count
247 assert_equal 0, JournalDetail.count
247 assert_equal 0, JournalDetail.count
248 assert_equal 0, Attachment.count, "Attachments were not deleted: #{Attachment.all.inspect}"
248 assert_equal 0, Attachment.count, "Attachments were not deleted: #{Attachment.all.inspect}"
249 assert_equal 0, EnabledModule.count
249 assert_equal 0, EnabledModule.count
250 assert_equal 0, IssueCategory.count
250 assert_equal 0, IssueCategory.count
251 assert_equal 0, IssueRelation.count
251 assert_equal 0, IssueRelation.count
252 assert_equal 0, Board.count
252 assert_equal 0, Board.count
253 assert_equal 0, Message.count
253 assert_equal 0, Message.count
254 assert_equal 0, News.count
254 assert_equal 0, News.count
255 assert_equal 0, Query.where("project_id IS NOT NULL").count
255 assert_equal 0, Query.where("project_id IS NOT NULL").count
256 assert_equal 0, Repository.count
256 assert_equal 0, Repository.count
257 assert_equal 0, Changeset.count
257 assert_equal 0, Changeset.count
258 assert_equal 0, Change.count
258 assert_equal 0, Change.count
259 assert_equal 0, Comment.count
259 assert_equal 0, Comment.count
260 assert_equal 0, TimeEntry.count
260 assert_equal 0, TimeEntry.count
261 assert_equal 0, Version.count
261 assert_equal 0, Version.count
262 assert_equal 0, Watcher.count
262 assert_equal 0, Watcher.count
263 assert_equal 0, Wiki.count
263 assert_equal 0, Wiki.count
264 assert_equal 0, WikiPage.count
264 assert_equal 0, WikiPage.count
265 assert_equal 0, WikiContent.count
265 assert_equal 0, WikiContent.count
266 assert_equal 0, WikiContent::Version.count
266 assert_equal 0, WikiContent::Version.count
267 assert_equal 0, Project.connection.select_all("SELECT * FROM projects_trackers").count
267 assert_equal 0, Project.connection.select_all("SELECT * FROM projects_trackers").count
268 assert_equal 0, Project.connection.select_all("SELECT * FROM custom_fields_projects").count
268 assert_equal 0, Project.connection.select_all("SELECT * FROM custom_fields_projects").count
269 assert_equal 0, CustomValue.where(:customized_type => ['Project', 'Issue', 'TimeEntry', 'Version']).count
269 assert_equal 0, CustomValue.where(:customized_type => ['Project', 'Issue', 'TimeEntry', 'Version']).count
270 end
270 end
271
271
272 def test_destroy_should_delete_time_entries_custom_values
272 def test_destroy_should_delete_time_entries_custom_values
273 project = Project.generate!
273 project = Project.generate!
274 time_entry = TimeEntry.generate!(:project => project, :custom_field_values => {10 => '1'})
274 time_entry = TimeEntry.generate!(:project => project, :custom_field_values => {10 => '1'})
275
275
276 assert_difference 'CustomValue.where(:customized_type => "TimeEntry").count', -1 do
276 assert_difference 'CustomValue.where(:customized_type => "TimeEntry").count', -1 do
277 assert project.destroy
277 assert project.destroy
278 end
278 end
279 end
279 end
280
280
281 def test_move_an_orphan_project_to_a_root_project
281 def test_move_an_orphan_project_to_a_root_project
282 sub = Project.find(2)
282 sub = Project.find(2)
283 sub.set_parent! @ecookbook
283 sub.set_parent! @ecookbook
284 assert_equal @ecookbook.id, sub.parent.id
284 assert_equal @ecookbook.id, sub.parent.id
285 @ecookbook.reload
285 @ecookbook.reload
286 assert_equal 4, @ecookbook.children.size
286 assert_equal 4, @ecookbook.children.size
287 end
287 end
288
288
289 def test_move_an_orphan_project_to_a_subproject
289 def test_move_an_orphan_project_to_a_subproject
290 sub = Project.find(2)
290 sub = Project.find(2)
291 assert sub.set_parent!(@ecookbook_sub1)
291 assert sub.set_parent!(@ecookbook_sub1)
292 end
292 end
293
293
294 def test_move_a_root_project_to_a_project
294 def test_move_a_root_project_to_a_project
295 sub = @ecookbook
295 sub = @ecookbook
296 assert sub.set_parent!(Project.find(2))
296 assert sub.set_parent!(Project.find(2))
297 end
297 end
298
298
299 def test_should_not_move_a_project_to_its_children
299 def test_should_not_move_a_project_to_its_children
300 sub = @ecookbook
300 sub = @ecookbook
301 assert !(sub.set_parent!(Project.find(3)))
301 assert !(sub.set_parent!(Project.find(3)))
302 end
302 end
303
303
304 def test_set_parent_should_add_roots_in_alphabetical_order
304 def test_set_parent_should_add_roots_in_alphabetical_order
305 ProjectCustomField.delete_all
305 ProjectCustomField.delete_all
306 Project.delete_all
306 Project.delete_all
307 Project.create!(:name => 'Project C', :identifier => 'project-c').set_parent!(nil)
307 Project.create!(:name => 'Project C', :identifier => 'project-c').set_parent!(nil)
308 Project.create!(:name => 'Project B', :identifier => 'project-b').set_parent!(nil)
308 Project.create!(:name => 'Project B', :identifier => 'project-b').set_parent!(nil)
309 Project.create!(:name => 'Project D', :identifier => 'project-d').set_parent!(nil)
309 Project.create!(:name => 'Project D', :identifier => 'project-d').set_parent!(nil)
310 Project.create!(:name => 'Project A', :identifier => 'project-a').set_parent!(nil)
310 Project.create!(:name => 'Project A', :identifier => 'project-a').set_parent!(nil)
311
311
312 assert_equal 4, Project.count
312 assert_equal 4, Project.count
313 assert_equal Project.all.sort_by(&:name), Project.all.sort_by(&:lft)
313 assert_equal Project.all.sort_by(&:name), Project.all.sort_by(&:lft)
314 end
314 end
315
315
316 def test_set_parent_should_add_children_in_alphabetical_order
316 def test_set_parent_should_add_children_in_alphabetical_order
317 ProjectCustomField.delete_all
317 ProjectCustomField.delete_all
318 parent = Project.create!(:name => 'Parent', :identifier => 'parent')
318 parent = Project.create!(:name => 'Parent', :identifier => 'parent')
319 Project.create!(:name => 'Project C', :identifier => 'project-c').set_parent!(parent)
319 Project.create!(:name => 'Project C', :identifier => 'project-c').set_parent!(parent)
320 Project.create!(:name => 'Project B', :identifier => 'project-b').set_parent!(parent)
320 Project.create!(:name => 'Project B', :identifier => 'project-b').set_parent!(parent)
321 Project.create!(:name => 'Project D', :identifier => 'project-d').set_parent!(parent)
321 Project.create!(:name => 'Project D', :identifier => 'project-d').set_parent!(parent)
322 Project.create!(:name => 'Project A', :identifier => 'project-a').set_parent!(parent)
322 Project.create!(:name => 'Project A', :identifier => 'project-a').set_parent!(parent)
323
323
324 parent.reload
324 parent.reload
325 assert_equal 4, parent.children.size
325 assert_equal 4, parent.children.size
326 assert_equal parent.children.sort_by(&:name), parent.children.to_a
326 assert_equal parent.children.sort_by(&:name), parent.children.to_a
327 end
327 end
328
328
329 def test_set_parent_should_update_issue_fixed_version_associations_when_a_fixed_version_is_moved_out_of_the_hierarchy
329 def test_set_parent_should_update_issue_fixed_version_associations_when_a_fixed_version_is_moved_out_of_the_hierarchy
330 # Parent issue with a hierarchy project's fixed version
330 # Parent issue with a hierarchy project's fixed version
331 parent_issue = Issue.find(1)
331 parent_issue = Issue.find(1)
332 parent_issue.update_attribute(:fixed_version_id, 4)
332 parent_issue.update_attribute(:fixed_version_id, 4)
333 parent_issue.reload
333 parent_issue.reload
334 assert_equal 4, parent_issue.fixed_version_id
334 assert_equal 4, parent_issue.fixed_version_id
335
335
336 # Should keep fixed versions for the issues
336 # Should keep fixed versions for the issues
337 issue_with_local_fixed_version = Issue.find(5)
337 issue_with_local_fixed_version = Issue.find(5)
338 issue_with_local_fixed_version.update_attribute(:fixed_version_id, 4)
338 issue_with_local_fixed_version.update_attribute(:fixed_version_id, 4)
339 issue_with_local_fixed_version.reload
339 issue_with_local_fixed_version.reload
340 assert_equal 4, issue_with_local_fixed_version.fixed_version_id
340 assert_equal 4, issue_with_local_fixed_version.fixed_version_id
341
341
342 # Local issue with hierarchy fixed_version
342 # Local issue with hierarchy fixed_version
343 issue_with_hierarchy_fixed_version = Issue.find(13)
343 issue_with_hierarchy_fixed_version = Issue.find(13)
344 issue_with_hierarchy_fixed_version.update_attribute(:fixed_version_id, 6)
344 issue_with_hierarchy_fixed_version.update_attribute(:fixed_version_id, 6)
345 issue_with_hierarchy_fixed_version.reload
345 issue_with_hierarchy_fixed_version.reload
346 assert_equal 6, issue_with_hierarchy_fixed_version.fixed_version_id
346 assert_equal 6, issue_with_hierarchy_fixed_version.fixed_version_id
347
347
348 # Move project out of the issue's hierarchy
348 # Move project out of the issue's hierarchy
349 moved_project = Project.find(3)
349 moved_project = Project.find(3)
350 moved_project.set_parent!(Project.find(2))
350 moved_project.set_parent!(Project.find(2))
351 parent_issue.reload
351 parent_issue.reload
352 issue_with_local_fixed_version.reload
352 issue_with_local_fixed_version.reload
353 issue_with_hierarchy_fixed_version.reload
353 issue_with_hierarchy_fixed_version.reload
354
354
355 assert_equal 4, issue_with_local_fixed_version.fixed_version_id, "Fixed version was not keep on an issue local to the moved project"
355 assert_equal 4, issue_with_local_fixed_version.fixed_version_id, "Fixed version was not keep on an issue local to the moved project"
356 assert_equal nil, issue_with_hierarchy_fixed_version.fixed_version_id, "Fixed version is still set after moving the Project out of the hierarchy where the version is defined in"
356 assert_equal nil, issue_with_hierarchy_fixed_version.fixed_version_id, "Fixed version is still set after moving the Project out of the hierarchy where the version is defined in"
357 assert_equal nil, parent_issue.fixed_version_id, "Fixed version is still set after moving the Version out of the hierarchy for the issue."
357 assert_equal nil, parent_issue.fixed_version_id, "Fixed version is still set after moving the Version out of the hierarchy for the issue."
358 end
358 end
359
359
360 def test_parent
360 def test_parent
361 p = Project.find(6).parent
361 p = Project.find(6).parent
362 assert p.is_a?(Project)
362 assert p.is_a?(Project)
363 assert_equal 5, p.id
363 assert_equal 5, p.id
364 end
364 end
365
365
366 def test_ancestors
366 def test_ancestors
367 a = Project.find(6).ancestors
367 a = Project.find(6).ancestors
368 assert a.first.is_a?(Project)
368 assert a.first.is_a?(Project)
369 assert_equal [1, 5], a.collect(&:id)
369 assert_equal [1, 5], a.collect(&:id)
370 end
370 end
371
371
372 def test_root
372 def test_root
373 r = Project.find(6).root
373 r = Project.find(6).root
374 assert r.is_a?(Project)
374 assert r.is_a?(Project)
375 assert_equal 1, r.id
375 assert_equal 1, r.id
376 end
376 end
377
377
378 def test_children
378 def test_children
379 c = Project.find(1).children
379 c = Project.find(1).children
380 assert c.first.is_a?(Project)
380 assert c.first.is_a?(Project)
381 assert_equal [5, 3, 4], c.collect(&:id)
381 assert_equal [5, 3, 4], c.collect(&:id)
382 end
382 end
383
383
384 def test_descendants
384 def test_descendants
385 d = Project.find(1).descendants
385 d = Project.find(1).descendants
386 assert d.first.is_a?(Project)
386 assert d.first.is_a?(Project)
387 assert_equal [5, 6, 3, 4], d.collect(&:id)
387 assert_equal [5, 6, 3, 4], d.collect(&:id)
388 end
388 end
389
389
390 def test_allowed_parents_should_be_empty_for_non_member_user
390 def test_allowed_parents_should_be_empty_for_non_member_user
391 Role.non_member.add_permission!(:add_project)
391 Role.non_member.add_permission!(:add_project)
392 user = User.find(9)
392 user = User.find(9)
393 assert user.memberships.empty?
393 assert user.memberships.empty?
394 User.current = user
394 User.current = user
395 assert Project.new.allowed_parents.compact.empty?
395 assert Project.new.allowed_parents.compact.empty?
396 end
396 end
397
397
398 def test_allowed_parents_with_add_subprojects_permission
398 def test_allowed_parents_with_add_subprojects_permission
399 Role.find(1).remove_permission!(:add_project)
399 Role.find(1).remove_permission!(:add_project)
400 Role.find(1).add_permission!(:add_subprojects)
400 Role.find(1).add_permission!(:add_subprojects)
401 User.current = User.find(2)
401 User.current = User.find(2)
402 # new project
402 # new project
403 assert !Project.new.allowed_parents.include?(nil)
403 assert !Project.new.allowed_parents.include?(nil)
404 assert Project.new.allowed_parents.include?(Project.find(1))
404 assert Project.new.allowed_parents.include?(Project.find(1))
405 # existing root project
405 # existing root project
406 assert Project.find(1).allowed_parents.include?(nil)
406 assert Project.find(1).allowed_parents.include?(nil)
407 # existing child
407 # existing child
408 assert Project.find(3).allowed_parents.include?(Project.find(1))
408 assert Project.find(3).allowed_parents.include?(Project.find(1))
409 assert !Project.find(3).allowed_parents.include?(nil)
409 assert !Project.find(3).allowed_parents.include?(nil)
410 end
410 end
411
411
412 def test_allowed_parents_with_add_project_permission
412 def test_allowed_parents_with_add_project_permission
413 Role.find(1).add_permission!(:add_project)
413 Role.find(1).add_permission!(:add_project)
414 Role.find(1).remove_permission!(:add_subprojects)
414 Role.find(1).remove_permission!(:add_subprojects)
415 User.current = User.find(2)
415 User.current = User.find(2)
416 # new project
416 # new project
417 assert Project.new.allowed_parents.include?(nil)
417 assert Project.new.allowed_parents.include?(nil)
418 assert !Project.new.allowed_parents.include?(Project.find(1))
418 assert !Project.new.allowed_parents.include?(Project.find(1))
419 # existing root project
419 # existing root project
420 assert Project.find(1).allowed_parents.include?(nil)
420 assert Project.find(1).allowed_parents.include?(nil)
421 # existing child
421 # existing child
422 assert Project.find(3).allowed_parents.include?(Project.find(1))
422 assert Project.find(3).allowed_parents.include?(Project.find(1))
423 assert Project.find(3).allowed_parents.include?(nil)
423 assert Project.find(3).allowed_parents.include?(nil)
424 end
424 end
425
425
426 def test_allowed_parents_with_add_project_and_subprojects_permission
426 def test_allowed_parents_with_add_project_and_subprojects_permission
427 Role.find(1).add_permission!(:add_project)
427 Role.find(1).add_permission!(:add_project)
428 Role.find(1).add_permission!(:add_subprojects)
428 Role.find(1).add_permission!(:add_subprojects)
429 User.current = User.find(2)
429 User.current = User.find(2)
430 # new project
430 # new project
431 assert Project.new.allowed_parents.include?(nil)
431 assert Project.new.allowed_parents.include?(nil)
432 assert Project.new.allowed_parents.include?(Project.find(1))
432 assert Project.new.allowed_parents.include?(Project.find(1))
433 # existing root project
433 # existing root project
434 assert Project.find(1).allowed_parents.include?(nil)
434 assert Project.find(1).allowed_parents.include?(nil)
435 # existing child
435 # existing child
436 assert Project.find(3).allowed_parents.include?(Project.find(1))
436 assert Project.find(3).allowed_parents.include?(Project.find(1))
437 assert Project.find(3).allowed_parents.include?(nil)
437 assert Project.find(3).allowed_parents.include?(nil)
438 end
438 end
439
439
440 def test_users_by_role
440 def test_users_by_role
441 users_by_role = Project.find(1).users_by_role
441 users_by_role = Project.find(1).users_by_role
442 assert_kind_of Hash, users_by_role
442 assert_kind_of Hash, users_by_role
443 role = Role.find(1)
443 role = Role.find(1)
444 assert_kind_of Array, users_by_role[role]
444 assert_kind_of Array, users_by_role[role]
445 assert users_by_role[role].include?(User.find(2))
445 assert users_by_role[role].include?(User.find(2))
446 end
446 end
447
447
448 def test_rolled_up_trackers
448 def test_rolled_up_trackers
449 parent = Project.find(1)
449 parent = Project.find(1)
450 parent.trackers = Tracker.find([1,2])
450 parent.trackers = Tracker.find([1,2])
451 child = parent.children.find(3)
451 child = parent.children.find(3)
452
452
453 assert_equal [1, 2], parent.tracker_ids
453 assert_equal [1, 2], parent.tracker_ids
454 assert_equal [2, 3], child.trackers.collect(&:id)
454 assert_equal [2, 3], child.trackers.collect(&:id)
455
455
456 assert_kind_of Tracker, parent.rolled_up_trackers.first
456 assert_kind_of Tracker, parent.rolled_up_trackers.first
457 assert_equal Tracker.find(1), parent.rolled_up_trackers.first
457 assert_equal Tracker.find(1), parent.rolled_up_trackers.first
458
458
459 assert_equal [1, 2, 3], parent.rolled_up_trackers.collect(&:id)
459 assert_equal [1, 2, 3], parent.rolled_up_trackers.collect(&:id)
460 assert_equal [2, 3], child.rolled_up_trackers.collect(&:id)
460 assert_equal [2, 3], child.rolled_up_trackers.collect(&:id)
461 end
461 end
462
462
463 def test_rolled_up_trackers_should_ignore_archived_subprojects
463 def test_rolled_up_trackers_should_ignore_archived_subprojects
464 parent = Project.find(1)
464 parent = Project.find(1)
465 parent.trackers = Tracker.find([1,2])
465 parent.trackers = Tracker.find([1,2])
466 child = parent.children.find(3)
466 child = parent.children.find(3)
467 child.trackers = Tracker.find([1,3])
467 child.trackers = Tracker.find([1,3])
468 parent.children.each(&:archive)
468 parent.children.each(&:archive)
469
469
470 assert_equal [1,2], parent.rolled_up_trackers.collect(&:id)
470 assert_equal [1,2], parent.rolled_up_trackers.collect(&:id)
471 end
471 end
472
472
473 test "#rolled_up_trackers should ignore projects with issue_tracking module disabled" do
473 test "#rolled_up_trackers should ignore projects with issue_tracking module disabled" do
474 parent = Project.generate!
474 parent = Project.generate!
475 parent.trackers = Tracker.find([1, 2])
475 parent.trackers = Tracker.find([1, 2])
476 child = Project.generate_with_parent!(parent)
476 child = Project.generate_with_parent!(parent)
477 child.trackers = Tracker.find([2, 3])
477 child.trackers = Tracker.find([2, 3])
478
478
479 assert_equal [1, 2, 3], parent.rolled_up_trackers.collect(&:id).sort
479 assert_equal [1, 2, 3], parent.rolled_up_trackers.collect(&:id).sort
480
480
481 assert child.disable_module!(:issue_tracking)
481 assert child.disable_module!(:issue_tracking)
482 parent.reload
482 parent.reload
483 assert_equal [1, 2], parent.rolled_up_trackers.collect(&:id).sort
483 assert_equal [1, 2], parent.rolled_up_trackers.collect(&:id).sort
484 end
484 end
485
485
486 test "#rolled_up_versions should include the versions for the current project" do
486 test "#rolled_up_versions should include the versions for the current project" do
487 project = Project.generate!
487 project = Project.generate!
488 parent_version_1 = Version.generate!(:project => project)
488 parent_version_1 = Version.generate!(:project => project)
489 parent_version_2 = Version.generate!(:project => project)
489 parent_version_2 = Version.generate!(:project => project)
490 assert_equal [parent_version_1, parent_version_2].sort,
490 assert_equal [parent_version_1, parent_version_2].sort,
491 project.rolled_up_versions.sort
491 project.rolled_up_versions.sort
492 end
492 end
493
493
494 test "#rolled_up_versions should include versions for a subproject" do
494 test "#rolled_up_versions should include versions for a subproject" do
495 project = Project.generate!
495 project = Project.generate!
496 parent_version_1 = Version.generate!(:project => project)
496 parent_version_1 = Version.generate!(:project => project)
497 parent_version_2 = Version.generate!(:project => project)
497 parent_version_2 = Version.generate!(:project => project)
498 subproject = Project.generate_with_parent!(project)
498 subproject = Project.generate_with_parent!(project)
499 subproject_version = Version.generate!(:project => subproject)
499 subproject_version = Version.generate!(:project => subproject)
500
500
501 assert_equal [parent_version_1, parent_version_2, subproject_version].sort,
501 assert_equal [parent_version_1, parent_version_2, subproject_version].sort,
502 project.rolled_up_versions.sort
502 project.rolled_up_versions.sort
503 end
503 end
504
504
505 test "#rolled_up_versions should include versions for a sub-subproject" do
505 test "#rolled_up_versions should include versions for a sub-subproject" do
506 project = Project.generate!
506 project = Project.generate!
507 parent_version_1 = Version.generate!(:project => project)
507 parent_version_1 = Version.generate!(:project => project)
508 parent_version_2 = Version.generate!(:project => project)
508 parent_version_2 = Version.generate!(:project => project)
509 subproject = Project.generate_with_parent!(project)
509 subproject = Project.generate_with_parent!(project)
510 sub_subproject = Project.generate_with_parent!(subproject)
510 sub_subproject = Project.generate_with_parent!(subproject)
511 sub_subproject_version = Version.generate!(:project => sub_subproject)
511 sub_subproject_version = Version.generate!(:project => sub_subproject)
512 project.reload
512 project.reload
513
513
514 assert_equal [parent_version_1, parent_version_2, sub_subproject_version].sort,
514 assert_equal [parent_version_1, parent_version_2, sub_subproject_version].sort,
515 project.rolled_up_versions.sort
515 project.rolled_up_versions.sort
516 end
516 end
517
517
518 test "#rolled_up_versions should only check active projects" do
518 test "#rolled_up_versions should only check active projects" do
519 project = Project.generate!
519 project = Project.generate!
520 parent_version_1 = Version.generate!(:project => project)
520 parent_version_1 = Version.generate!(:project => project)
521 parent_version_2 = Version.generate!(:project => project)
521 parent_version_2 = Version.generate!(:project => project)
522 subproject = Project.generate_with_parent!(project)
522 subproject = Project.generate_with_parent!(project)
523 subproject_version = Version.generate!(:project => subproject)
523 subproject_version = Version.generate!(:project => subproject)
524 assert subproject.archive
524 assert subproject.archive
525 project.reload
525 project.reload
526
526
527 assert !subproject.active?
527 assert !subproject.active?
528 assert_equal [parent_version_1, parent_version_2].sort,
528 assert_equal [parent_version_1, parent_version_2].sort,
529 project.rolled_up_versions.sort
529 project.rolled_up_versions.sort
530 end
530 end
531
531
532 def test_shared_versions_none_sharing
532 def test_shared_versions_none_sharing
533 p = Project.find(5)
533 p = Project.find(5)
534 v = Version.create!(:name => 'none_sharing', :project => p, :sharing => 'none')
534 v = Version.create!(:name => 'none_sharing', :project => p, :sharing => 'none')
535 assert p.shared_versions.include?(v)
535 assert p.shared_versions.include?(v)
536 assert !p.children.first.shared_versions.include?(v)
536 assert !p.children.first.shared_versions.include?(v)
537 assert !p.root.shared_versions.include?(v)
537 assert !p.root.shared_versions.include?(v)
538 assert !p.siblings.first.shared_versions.include?(v)
538 assert !p.siblings.first.shared_versions.include?(v)
539 assert !p.root.siblings.first.shared_versions.include?(v)
539 assert !p.root.siblings.first.shared_versions.include?(v)
540 end
540 end
541
541
542 def test_shared_versions_descendants_sharing
542 def test_shared_versions_descendants_sharing
543 p = Project.find(5)
543 p = Project.find(5)
544 v = Version.create!(:name => 'descendants_sharing', :project => p, :sharing => 'descendants')
544 v = Version.create!(:name => 'descendants_sharing', :project => p, :sharing => 'descendants')
545 assert p.shared_versions.include?(v)
545 assert p.shared_versions.include?(v)
546 assert p.children.first.shared_versions.include?(v)
546 assert p.children.first.shared_versions.include?(v)
547 assert !p.root.shared_versions.include?(v)
547 assert !p.root.shared_versions.include?(v)
548 assert !p.siblings.first.shared_versions.include?(v)
548 assert !p.siblings.first.shared_versions.include?(v)
549 assert !p.root.siblings.first.shared_versions.include?(v)
549 assert !p.root.siblings.first.shared_versions.include?(v)
550 end
550 end
551
551
552 def test_shared_versions_hierarchy_sharing
552 def test_shared_versions_hierarchy_sharing
553 p = Project.find(5)
553 p = Project.find(5)
554 v = Version.create!(:name => 'hierarchy_sharing', :project => p, :sharing => 'hierarchy')
554 v = Version.create!(:name => 'hierarchy_sharing', :project => p, :sharing => 'hierarchy')
555 assert p.shared_versions.include?(v)
555 assert p.shared_versions.include?(v)
556 assert p.children.first.shared_versions.include?(v)
556 assert p.children.first.shared_versions.include?(v)
557 assert p.root.shared_versions.include?(v)
557 assert p.root.shared_versions.include?(v)
558 assert !p.siblings.first.shared_versions.include?(v)
558 assert !p.siblings.first.shared_versions.include?(v)
559 assert !p.root.siblings.first.shared_versions.include?(v)
559 assert !p.root.siblings.first.shared_versions.include?(v)
560 end
560 end
561
561
562 def test_shared_versions_tree_sharing
562 def test_shared_versions_tree_sharing
563 p = Project.find(5)
563 p = Project.find(5)
564 v = Version.create!(:name => 'tree_sharing', :project => p, :sharing => 'tree')
564 v = Version.create!(:name => 'tree_sharing', :project => p, :sharing => 'tree')
565 assert p.shared_versions.include?(v)
565 assert p.shared_versions.include?(v)
566 assert p.children.first.shared_versions.include?(v)
566 assert p.children.first.shared_versions.include?(v)
567 assert p.root.shared_versions.include?(v)
567 assert p.root.shared_versions.include?(v)
568 assert p.siblings.first.shared_versions.include?(v)
568 assert p.siblings.first.shared_versions.include?(v)
569 assert !p.root.siblings.first.shared_versions.include?(v)
569 assert !p.root.siblings.first.shared_versions.include?(v)
570 end
570 end
571
571
572 def test_shared_versions_system_sharing
572 def test_shared_versions_system_sharing
573 p = Project.find(5)
573 p = Project.find(5)
574 v = Version.create!(:name => 'system_sharing', :project => p, :sharing => 'system')
574 v = Version.create!(:name => 'system_sharing', :project => p, :sharing => 'system')
575 assert p.shared_versions.include?(v)
575 assert p.shared_versions.include?(v)
576 assert p.children.first.shared_versions.include?(v)
576 assert p.children.first.shared_versions.include?(v)
577 assert p.root.shared_versions.include?(v)
577 assert p.root.shared_versions.include?(v)
578 assert p.siblings.first.shared_versions.include?(v)
578 assert p.siblings.first.shared_versions.include?(v)
579 assert p.root.siblings.first.shared_versions.include?(v)
579 assert p.root.siblings.first.shared_versions.include?(v)
580 end
580 end
581
581
582 def test_shared_versions
582 def test_shared_versions
583 parent = Project.find(1)
583 parent = Project.find(1)
584 child = parent.children.find(3)
584 child = parent.children.find(3)
585 private_child = parent.children.find(5)
585 private_child = parent.children.find(5)
586
586
587 assert_equal [1,2,3], parent.version_ids.sort
587 assert_equal [1,2,3], parent.version_ids.sort
588 assert_equal [4], child.version_ids
588 assert_equal [4], child.version_ids
589 assert_equal [6], private_child.version_ids
589 assert_equal [6], private_child.version_ids
590 assert_equal [7], Version.where(:sharing => 'system').collect(&:id)
590 assert_equal [7], Version.where(:sharing => 'system').collect(&:id)
591
591
592 assert_equal 6, parent.shared_versions.size
592 assert_equal 6, parent.shared_versions.size
593 parent.shared_versions.each do |version|
593 parent.shared_versions.each do |version|
594 assert_kind_of Version, version
594 assert_kind_of Version, version
595 end
595 end
596
596
597 assert_equal [1,2,3,4,6,7], parent.shared_versions.collect(&:id).sort
597 assert_equal [1,2,3,4,6,7], parent.shared_versions.collect(&:id).sort
598 end
598 end
599
599
600 def test_shared_versions_should_ignore_archived_subprojects
600 def test_shared_versions_should_ignore_archived_subprojects
601 parent = Project.find(1)
601 parent = Project.find(1)
602 child = parent.children.find(3)
602 child = parent.children.find(3)
603 child.archive
603 child.archive
604 parent.reload
604 parent.reload
605
605
606 assert_equal [1,2,3], parent.version_ids.sort
606 assert_equal [1,2,3], parent.version_ids.sort
607 assert_equal [4], child.version_ids
607 assert_equal [4], child.version_ids
608 assert !parent.shared_versions.collect(&:id).include?(4)
608 assert !parent.shared_versions.collect(&:id).include?(4)
609 end
609 end
610
610
611 def test_shared_versions_visible_to_user
611 def test_shared_versions_visible_to_user
612 user = User.find(3)
612 user = User.find(3)
613 parent = Project.find(1)
613 parent = Project.find(1)
614 child = parent.children.find(5)
614 child = parent.children.find(5)
615
615
616 assert_equal [1,2,3], parent.version_ids.sort
616 assert_equal [1,2,3], parent.version_ids.sort
617 assert_equal [6], child.version_ids
617 assert_equal [6], child.version_ids
618
618
619 versions = parent.shared_versions.visible(user)
619 versions = parent.shared_versions.visible(user)
620
620
621 assert_equal 4, versions.size
621 assert_equal 4, versions.size
622 versions.each do |version|
622 versions.each do |version|
623 assert_kind_of Version, version
623 assert_kind_of Version, version
624 end
624 end
625
625
626 assert !versions.collect(&:id).include?(6)
626 assert !versions.collect(&:id).include?(6)
627 end
627 end
628
628
629 def test_shared_versions_for_new_project_should_include_system_shared_versions
629 def test_shared_versions_for_new_project_should_include_system_shared_versions
630 p = Project.find(5)
630 p = Project.find(5)
631 v = Version.create!(:name => 'system_sharing', :project => p, :sharing => 'system')
631 v = Version.create!(:name => 'system_sharing', :project => p, :sharing => 'system')
632
632
633 assert_include v, Project.new.shared_versions
633 assert_include v, Project.new.shared_versions
634 end
634 end
635
635
636 def test_next_identifier
636 def test_next_identifier
637 ProjectCustomField.delete_all
637 ProjectCustomField.delete_all
638 Project.create!(:name => 'last', :identifier => 'p2008040')
638 Project.create!(:name => 'last', :identifier => 'p2008040')
639 assert_equal 'p2008041', Project.next_identifier
639 assert_equal 'p2008041', Project.next_identifier
640 end
640 end
641
641
642 def test_next_identifier_first_project
642 def test_next_identifier_first_project
643 Project.delete_all
643 Project.delete_all
644 assert_nil Project.next_identifier
644 assert_nil Project.next_identifier
645 end
645 end
646
646
647 def test_enabled_module_names
647 def test_enabled_module_names
648 with_settings :default_projects_modules => ['issue_tracking', 'repository'] do
648 with_settings :default_projects_modules => ['issue_tracking', 'repository'] do
649 project = Project.new
649 project = Project.new
650
650
651 project.enabled_module_names = %w(issue_tracking news)
651 project.enabled_module_names = %w(issue_tracking news)
652 assert_equal %w(issue_tracking news), project.enabled_module_names.sort
652 assert_equal %w(issue_tracking news), project.enabled_module_names.sort
653 end
653 end
654 end
654 end
655
655
656 def test_enabled_modules_names_with_nil_should_clear_modules
656 def test_enabled_modules_names_with_nil_should_clear_modules
657 p = Project.find(1)
657 p = Project.find(1)
658 p.enabled_module_names = nil
658 p.enabled_module_names = nil
659 assert_equal [], p.enabled_modules
659 assert_equal [], p.enabled_modules
660 end
660 end
661
661
662 test "enabled_modules should define module by names and preserve ids" do
662 test "enabled_modules should define module by names and preserve ids" do
663 @project = Project.find(1)
663 @project = Project.find(1)
664 # Remove one module
664 # Remove one module
665 modules = @project.enabled_modules.slice(0..-2)
665 modules = @project.enabled_modules.slice(0..-2)
666 assert modules.any?
666 assert modules.any?
667 assert_difference 'EnabledModule.count', -1 do
667 assert_difference 'EnabledModule.count', -1 do
668 @project.enabled_module_names = modules.collect(&:name)
668 @project.enabled_module_names = modules.collect(&:name)
669 end
669 end
670 @project.reload
670 @project.reload
671 # Ids should be preserved
671 # Ids should be preserved
672 assert_equal @project.enabled_module_ids.sort, modules.collect(&:id).sort
672 assert_equal @project.enabled_module_ids.sort, modules.collect(&:id).sort
673 end
673 end
674
674
675 test "enabled_modules should enable a module" do
675 test "enabled_modules should enable a module" do
676 @project = Project.find(1)
676 @project = Project.find(1)
677 @project.enabled_module_names = []
677 @project.enabled_module_names = []
678 @project.reload
678 @project.reload
679 assert_equal [], @project.enabled_module_names
679 assert_equal [], @project.enabled_module_names
680 #with string
680 #with string
681 @project.enable_module!("issue_tracking")
681 @project.enable_module!("issue_tracking")
682 assert_equal ["issue_tracking"], @project.enabled_module_names
682 assert_equal ["issue_tracking"], @project.enabled_module_names
683 #with symbol
683 #with symbol
684 @project.enable_module!(:gantt)
684 @project.enable_module!(:gantt)
685 assert_equal ["issue_tracking", "gantt"], @project.enabled_module_names
685 assert_equal ["issue_tracking", "gantt"], @project.enabled_module_names
686 #don't add a module twice
686 #don't add a module twice
687 @project.enable_module!("issue_tracking")
687 @project.enable_module!("issue_tracking")
688 assert_equal ["issue_tracking", "gantt"], @project.enabled_module_names
688 assert_equal ["issue_tracking", "gantt"], @project.enabled_module_names
689 end
689 end
690
690
691 test "enabled_modules should disable a module" do
691 test "enabled_modules should disable a module" do
692 @project = Project.find(1)
692 @project = Project.find(1)
693 #with string
693 #with string
694 assert @project.enabled_module_names.include?("issue_tracking")
694 assert @project.enabled_module_names.include?("issue_tracking")
695 @project.disable_module!("issue_tracking")
695 @project.disable_module!("issue_tracking")
696 assert ! @project.reload.enabled_module_names.include?("issue_tracking")
696 assert ! @project.reload.enabled_module_names.include?("issue_tracking")
697 #with symbol
697 #with symbol
698 assert @project.enabled_module_names.include?("gantt")
698 assert @project.enabled_module_names.include?("gantt")
699 @project.disable_module!(:gantt)
699 @project.disable_module!(:gantt)
700 assert ! @project.reload.enabled_module_names.include?("gantt")
700 assert ! @project.reload.enabled_module_names.include?("gantt")
701 #with EnabledModule object
701 #with EnabledModule object
702 first_module = @project.enabled_modules.first
702 first_module = @project.enabled_modules.first
703 @project.disable_module!(first_module)
703 @project.disable_module!(first_module)
704 assert ! @project.reload.enabled_module_names.include?(first_module.name)
704 assert ! @project.reload.enabled_module_names.include?(first_module.name)
705 end
705 end
706
706
707 def test_enabled_module_names_should_not_recreate_enabled_modules
707 def test_enabled_module_names_should_not_recreate_enabled_modules
708 project = Project.find(1)
708 project = Project.find(1)
709 # Remove one module
709 # Remove one module
710 modules = project.enabled_modules.slice(0..-2)
710 modules = project.enabled_modules.slice(0..-2)
711 assert modules.any?
711 assert modules.any?
712 assert_difference 'EnabledModule.count', -1 do
712 assert_difference 'EnabledModule.count', -1 do
713 project.enabled_module_names = modules.collect(&:name)
713 project.enabled_module_names = modules.collect(&:name)
714 end
714 end
715 project.reload
715 project.reload
716 # Ids should be preserved
716 # Ids should be preserved
717 assert_equal project.enabled_module_ids.sort, modules.collect(&:id).sort
717 assert_equal project.enabled_module_ids.sort, modules.collect(&:id).sort
718 end
718 end
719
719
720 def test_copy_from_existing_project
720 def test_copy_from_existing_project
721 source_project = Project.find(1)
721 source_project = Project.find(1)
722 copied_project = Project.copy_from(1)
722 copied_project = Project.copy_from(1)
723
723
724 assert copied_project
724 assert copied_project
725 # Cleared attributes
725 # Cleared attributes
726 assert copied_project.id.blank?
726 assert copied_project.id.blank?
727 assert copied_project.name.blank?
727 assert copied_project.name.blank?
728 assert copied_project.identifier.blank?
728 assert copied_project.identifier.blank?
729
729
730 # Duplicated attributes
730 # Duplicated attributes
731 assert_equal source_project.description, copied_project.description
731 assert_equal source_project.description, copied_project.description
732 assert_equal source_project.trackers, copied_project.trackers
732 assert_equal source_project.trackers, copied_project.trackers
733
733
734 # Default attributes
734 # Default attributes
735 assert_equal 1, copied_project.status
735 assert_equal 1, copied_project.status
736 end
736 end
737
737
738 def test_copy_from_should_copy_enabled_modules
738 def test_copy_from_should_copy_enabled_modules
739 source = Project.generate!
739 source = Project.generate!
740 source.enabled_module_names = %w(issue_tracking wiki)
740 source.enabled_module_names = %w(issue_tracking wiki)
741
741
742 copy = Project.copy_from(source)
742 copy = Project.copy_from(source)
743 copy.name = 'Copy'
743 copy.name = 'Copy'
744 copy.identifier = 'copy'
744 copy.identifier = 'copy'
745 assert_difference 'EnabledModule.count', 2 do
745 assert_difference 'EnabledModule.count', 2 do
746 copy.save!
746 copy.save!
747 end
747 end
748 assert_equal 2, copy.reload.enabled_modules.count
748 assert_equal 2, copy.reload.enabled_modules.count
749 assert_equal 2, source.reload.enabled_modules.count
749 assert_equal 2, source.reload.enabled_modules.count
750 end
750 end
751
751
752 def test_activities_should_use_the_system_activities
752 def test_activities_should_use_the_system_activities
753 project = Project.find(1)
753 project = Project.find(1)
754 assert_equal project.activities.to_a, TimeEntryActivity.where(:active => true).to_a
754 assert_equal project.activities.to_a, TimeEntryActivity.where(:active => true).to_a
755 assert_kind_of ActiveRecord::Relation, project.activities
755 assert_kind_of ActiveRecord::Relation, project.activities
756 end
756 end
757
757
758
758
759 def test_activities_should_use_the_project_specific_activities
759 def test_activities_should_use_the_project_specific_activities
760 project = Project.find(1)
760 project = Project.find(1)
761 overridden_activity = TimeEntryActivity.new({:name => "Project", :project => project})
761 overridden_activity = TimeEntryActivity.new({:name => "Project", :project => project})
762 assert overridden_activity.save!
762 assert overridden_activity.save!
763
763
764 assert project.activities.include?(overridden_activity), "Project specific Activity not found"
764 assert project.activities.include?(overridden_activity), "Project specific Activity not found"
765 assert_kind_of ActiveRecord::Relation, project.activities
765 assert_kind_of ActiveRecord::Relation, project.activities
766 end
766 end
767
767
768 def test_activities_should_not_include_the_inactive_project_specific_activities
768 def test_activities_should_not_include_the_inactive_project_specific_activities
769 project = Project.find(1)
769 project = Project.find(1)
770 overridden_activity = TimeEntryActivity.new({:name => "Project", :project => project, :parent => TimeEntryActivity.first, :active => false})
770 overridden_activity = TimeEntryActivity.new({:name => "Project", :project => project, :parent => TimeEntryActivity.first, :active => false})
771 assert overridden_activity.save!
771 assert overridden_activity.save!
772
772
773 assert !project.activities.include?(overridden_activity), "Inactive Project specific Activity found"
773 assert !project.activities.include?(overridden_activity), "Inactive Project specific Activity found"
774 end
774 end
775
775
776 def test_activities_should_not_include_project_specific_activities_from_other_projects
776 def test_activities_should_not_include_project_specific_activities_from_other_projects
777 project = Project.find(1)
777 project = Project.find(1)
778 overridden_activity = TimeEntryActivity.new({:name => "Project", :project => Project.find(2)})
778 overridden_activity = TimeEntryActivity.new({:name => "Project", :project => Project.find(2)})
779 assert overridden_activity.save!
779 assert overridden_activity.save!
780
780
781 assert !project.activities.include?(overridden_activity), "Project specific Activity found on a different project"
781 assert !project.activities.include?(overridden_activity), "Project specific Activity found on a different project"
782 end
782 end
783
783
784 def test_activities_should_handle_nils
784 def test_activities_should_handle_nils
785 overridden_activity = TimeEntryActivity.new({:name => "Project", :project => Project.find(1), :parent => TimeEntryActivity.first})
785 overridden_activity = TimeEntryActivity.new({:name => "Project", :project => Project.find(1), :parent => TimeEntryActivity.first})
786 TimeEntryActivity.delete_all
786 TimeEntryActivity.delete_all
787
787
788 # No activities
788 # No activities
789 project = Project.find(1)
789 project = Project.find(1)
790 assert project.activities.empty?
790 assert project.activities.empty?
791
791
792 # No system, one overridden
792 # No system, one overridden
793 assert overridden_activity.save!
793 assert overridden_activity.save!
794 project.reload
794 project.reload
795 assert_equal [overridden_activity], project.activities
795 assert_equal [overridden_activity], project.activities
796 end
796 end
797
797
798 def test_activities_should_override_system_activities_with_project_activities
798 def test_activities_should_override_system_activities_with_project_activities
799 project = Project.find(1)
799 project = Project.find(1)
800 parent_activity = TimeEntryActivity.first
800 parent_activity = TimeEntryActivity.first
801 overridden_activity = TimeEntryActivity.new({:name => "Project", :project => project, :parent => parent_activity})
801 overridden_activity = TimeEntryActivity.new({:name => "Project", :project => project, :parent => parent_activity})
802 assert overridden_activity.save!
802 assert overridden_activity.save!
803
803
804 assert project.activities.include?(overridden_activity), "Project specific Activity not found"
804 assert project.activities.include?(overridden_activity), "Project specific Activity not found"
805 assert !project.activities.include?(parent_activity), "System Activity found when it should have been overridden"
805 assert !project.activities.include?(parent_activity), "System Activity found when it should have been overridden"
806 end
806 end
807
807
808 def test_activities_should_include_inactive_activities_if_specified
808 def test_activities_should_include_inactive_activities_if_specified
809 project = Project.find(1)
809 project = Project.find(1)
810 overridden_activity = TimeEntryActivity.new({:name => "Project", :project => project, :parent => TimeEntryActivity.first, :active => false})
810 overridden_activity = TimeEntryActivity.new({:name => "Project", :project => project, :parent => TimeEntryActivity.first, :active => false})
811 assert overridden_activity.save!
811 assert overridden_activity.save!
812
812
813 assert project.activities(true).include?(overridden_activity), "Inactive Project specific Activity not found"
813 assert project.activities(true).include?(overridden_activity), "Inactive Project specific Activity not found"
814 end
814 end
815
815
816 test 'activities should not include active System activities if the project has an override that is inactive' do
816 test 'activities should not include active System activities if the project has an override that is inactive' do
817 project = Project.find(1)
817 project = Project.find(1)
818 system_activity = TimeEntryActivity.find_by_name('Design')
818 system_activity = TimeEntryActivity.find_by_name('Design')
819 assert system_activity.active?
819 assert system_activity.active?
820 overridden_activity = TimeEntryActivity.create!(:name => "Project", :project => project, :parent => system_activity, :active => false)
820 overridden_activity = TimeEntryActivity.create!(:name => "Project", :project => project, :parent => system_activity, :active => false)
821 assert overridden_activity.save!
821 assert overridden_activity.save!
822
822
823 assert !project.activities.include?(overridden_activity), "Inactive Project specific Activity not found"
823 assert !project.activities.include?(overridden_activity), "Inactive Project specific Activity not found"
824 assert !project.activities.include?(system_activity), "System activity found when the project has an inactive override"
824 assert !project.activities.include?(system_activity), "System activity found when the project has an inactive override"
825 end
825 end
826
826
827 def test_close_completed_versions
827 def test_close_completed_versions
828 Version.update_all("status = 'open'")
828 Version.update_all("status = 'open'")
829 project = Project.find(1)
829 project = Project.find(1)
830 assert_not_nil project.versions.detect {|v| v.completed? && v.status == 'open'}
830 assert_not_nil project.versions.detect {|v| v.completed? && v.status == 'open'}
831 assert_not_nil project.versions.detect {|v| !v.completed? && v.status == 'open'}
831 assert_not_nil project.versions.detect {|v| !v.completed? && v.status == 'open'}
832 project.close_completed_versions
832 project.close_completed_versions
833 project.reload
833 project.reload
834 assert_nil project.versions.detect {|v| v.completed? && v.status != 'closed'}
834 assert_nil project.versions.detect {|v| v.completed? && v.status != 'closed'}
835 assert_not_nil project.versions.detect {|v| !v.completed? && v.status == 'open'}
835 assert_not_nil project.versions.detect {|v| !v.completed? && v.status == 'open'}
836 end
836 end
837
837
838 test "#start_date should be nil if there are no issues on the project" do
838 test "#start_date should be nil if there are no issues on the project" do
839 project = Project.generate!
839 project = Project.generate!
840 assert_nil project.start_date
840 assert_nil project.start_date
841 end
841 end
842
842
843 test "#start_date should be nil when issues have no start date" do
843 test "#start_date should be nil when issues have no start date" do
844 project = Project.generate!
844 project = Project.generate!
845 project.trackers << Tracker.generate!
845 project.trackers << Tracker.generate!
846 early = 7.days.ago.to_date
846 early = 7.days.ago.to_date
847 Issue.generate!(:project => project, :start_date => nil)
847 Issue.generate!(:project => project, :start_date => nil)
848
848
849 assert_nil project.start_date
849 assert_nil project.start_date
850 end
850 end
851
851
852 test "#start_date should be the earliest start date of it's issues" do
852 test "#start_date should be the earliest start date of it's issues" do
853 project = Project.generate!
853 project = Project.generate!
854 project.trackers << Tracker.generate!
854 project.trackers << Tracker.generate!
855 early = 7.days.ago.to_date
855 early = 7.days.ago.to_date
856 Issue.generate!(:project => project, :start_date => Date.today)
856 Issue.generate!(:project => project, :start_date => Date.today)
857 Issue.generate!(:project => project, :start_date => early)
857 Issue.generate!(:project => project, :start_date => early)
858
858
859 assert_equal early, project.start_date
859 assert_equal early, project.start_date
860 end
860 end
861
861
862 test "#due_date should be nil if there are no issues on the project" do
862 test "#due_date should be nil if there are no issues on the project" do
863 project = Project.generate!
863 project = Project.generate!
864 assert_nil project.due_date
864 assert_nil project.due_date
865 end
865 end
866
866
867 test "#due_date should be nil if there are no issues with due dates" do
867 test "#due_date should be nil if there are no issues with due dates" do
868 project = Project.generate!
868 project = Project.generate!
869 project.trackers << Tracker.generate!
869 project.trackers << Tracker.generate!
870 Issue.generate!(:project => project, :due_date => nil)
870 Issue.generate!(:project => project, :due_date => nil)
871
871
872 assert_nil project.due_date
872 assert_nil project.due_date
873 end
873 end
874
874
875 test "#due_date should be the latest due date of it's issues" do
875 test "#due_date should be the latest due date of it's issues" do
876 project = Project.generate!
876 project = Project.generate!
877 project.trackers << Tracker.generate!
877 project.trackers << Tracker.generate!
878 future = 7.days.from_now.to_date
878 future = 7.days.from_now.to_date
879 Issue.generate!(:project => project, :due_date => future)
879 Issue.generate!(:project => project, :due_date => future)
880 Issue.generate!(:project => project, :due_date => Date.today)
880 Issue.generate!(:project => project, :due_date => Date.today)
881
881
882 assert_equal future, project.due_date
882 assert_equal future, project.due_date
883 end
883 end
884
884
885 test "#due_date should be the latest due date of it's versions" do
885 test "#due_date should be the latest due date of it's versions" do
886 project = Project.generate!
886 project = Project.generate!
887 future = 7.days.from_now.to_date
887 future = 7.days.from_now.to_date
888 project.versions << Version.generate!(:effective_date => future)
888 project.versions << Version.generate!(:effective_date => future)
889 project.versions << Version.generate!(:effective_date => Date.today)
889 project.versions << Version.generate!(:effective_date => Date.today)
890
890
891 assert_equal future, project.due_date
891 assert_equal future, project.due_date
892 end
892 end
893
893
894 test "#due_date should pick the latest date from it's issues and versions" do
894 test "#due_date should pick the latest date from it's issues and versions" do
895 project = Project.generate!
895 project = Project.generate!
896 project.trackers << Tracker.generate!
896 project.trackers << Tracker.generate!
897 future = 7.days.from_now.to_date
897 future = 7.days.from_now.to_date
898 far_future = 14.days.from_now.to_date
898 far_future = 14.days.from_now.to_date
899 Issue.generate!(:project => project, :due_date => far_future)
899 Issue.generate!(:project => project, :due_date => far_future)
900 project.versions << Version.generate!(:effective_date => future)
900 project.versions << Version.generate!(:effective_date => future)
901
901
902 assert_equal far_future, project.due_date
902 assert_equal far_future, project.due_date
903 end
903 end
904
904
905 test "#completed_percent with no versions should be 100" do
905 test "#completed_percent with no versions should be 100" do
906 project = Project.generate!
906 project = Project.generate!
907 assert_equal 100, project.completed_percent
907 assert_equal 100, project.completed_percent
908 end
908 end
909
909
910 test "#completed_percent with versions should return 0 if the versions have no issues" do
910 test "#completed_percent with versions should return 0 if the versions have no issues" do
911 project = Project.generate!
911 project = Project.generate!
912 Version.generate!(:project => project)
912 Version.generate!(:project => project)
913 Version.generate!(:project => project)
913 Version.generate!(:project => project)
914
914
915 assert_equal 0, project.completed_percent
915 assert_equal 0, project.completed_percent
916 end
916 end
917
917
918 test "#completed_percent with versions should return 100 if the version has only closed issues" do
918 test "#completed_percent with versions should return 100 if the version has only closed issues" do
919 project = Project.generate!
919 project = Project.generate!
920 project.trackers << Tracker.generate!
920 project.trackers << Tracker.generate!
921 v1 = Version.generate!(:project => project)
921 v1 = Version.generate!(:project => project)
922 Issue.generate!(:project => project, :status => IssueStatus.find_by_name('Closed'), :fixed_version => v1)
922 Issue.generate!(:project => project, :status => IssueStatus.find_by_name('Closed'), :fixed_version => v1)
923 v2 = Version.generate!(:project => project)
923 v2 = Version.generate!(:project => project)
924 Issue.generate!(:project => project, :status => IssueStatus.find_by_name('Closed'), :fixed_version => v2)
924 Issue.generate!(:project => project, :status => IssueStatus.find_by_name('Closed'), :fixed_version => v2)
925
925
926 assert_equal 100, project.completed_percent
926 assert_equal 100, project.completed_percent
927 end
927 end
928
928
929 test "#completed_percent with versions should return the averaged completed percent of the versions (not weighted)" do
929 test "#completed_percent with versions should return the averaged completed percent of the versions (not weighted)" do
930 project = Project.generate!
930 project = Project.generate!
931 project.trackers << Tracker.generate!
931 project.trackers << Tracker.generate!
932 v1 = Version.generate!(:project => project)
932 v1 = Version.generate!(:project => project)
933 Issue.generate!(:project => project, :status => IssueStatus.find_by_name('New'), :estimated_hours => 10, :done_ratio => 50, :fixed_version => v1)
933 Issue.generate!(:project => project, :status => IssueStatus.find_by_name('New'), :estimated_hours => 10, :done_ratio => 50, :fixed_version => v1)
934 v2 = Version.generate!(:project => project)
934 v2 = Version.generate!(:project => project)
935 Issue.generate!(:project => project, :status => IssueStatus.find_by_name('New'), :estimated_hours => 10, :done_ratio => 50, :fixed_version => v2)
935 Issue.generate!(:project => project, :status => IssueStatus.find_by_name('New'), :estimated_hours => 10, :done_ratio => 50, :fixed_version => v2)
936
936
937 assert_equal 50, project.completed_percent
937 assert_equal 50, project.completed_percent
938 end
938 end
939
939
940 test "#notified_users" do
940 test "#notified_users" do
941 project = Project.generate!
941 project = Project.generate!
942 role = Role.generate!
942 role = Role.generate!
943
943
944 user_with_membership_notification = User.generate!(:mail_notification => 'selected')
944 user_with_membership_notification = User.generate!(:mail_notification => 'selected')
945 Member.create!(:project => project, :roles => [role], :principal => user_with_membership_notification, :mail_notification => true)
945 Member.create!(:project => project, :roles => [role], :principal => user_with_membership_notification, :mail_notification => true)
946
946
947 all_events_user = User.generate!(:mail_notification => 'all')
947 all_events_user = User.generate!(:mail_notification => 'all')
948 Member.create!(:project => project, :roles => [role], :principal => all_events_user)
948 Member.create!(:project => project, :roles => [role], :principal => all_events_user)
949
949
950 no_events_user = User.generate!(:mail_notification => 'none')
950 no_events_user = User.generate!(:mail_notification => 'none')
951 Member.create!(:project => project, :roles => [role], :principal => no_events_user)
951 Member.create!(:project => project, :roles => [role], :principal => no_events_user)
952
952
953 only_my_events_user = User.generate!(:mail_notification => 'only_my_events')
953 only_my_events_user = User.generate!(:mail_notification => 'only_my_events')
954 Member.create!(:project => project, :roles => [role], :principal => only_my_events_user)
954 Member.create!(:project => project, :roles => [role], :principal => only_my_events_user)
955
955
956 only_assigned_user = User.generate!(:mail_notification => 'only_assigned')
956 only_assigned_user = User.generate!(:mail_notification => 'only_assigned')
957 Member.create!(:project => project, :roles => [role], :principal => only_assigned_user)
957 Member.create!(:project => project, :roles => [role], :principal => only_assigned_user)
958
958
959 only_owned_user = User.generate!(:mail_notification => 'only_owner')
959 only_owned_user = User.generate!(:mail_notification => 'only_owner')
960 Member.create!(:project => project, :roles => [role], :principal => only_owned_user)
960 Member.create!(:project => project, :roles => [role], :principal => only_owned_user)
961
961
962 assert project.notified_users.include?(user_with_membership_notification), "should include members with a mail notification"
962 assert project.notified_users.include?(user_with_membership_notification), "should include members with a mail notification"
963 assert project.notified_users.include?(all_events_user), "should include users with the 'all' notification option"
963 assert project.notified_users.include?(all_events_user), "should include users with the 'all' notification option"
964 assert !project.notified_users.include?(no_events_user), "should not include users with the 'none' notification option"
964 assert !project.notified_users.include?(no_events_user), "should not include users with the 'none' notification option"
965 assert !project.notified_users.include?(only_my_events_user), "should not include users with the 'only_my_events' notification option"
965 assert !project.notified_users.include?(only_my_events_user), "should not include users with the 'only_my_events' notification option"
966 assert !project.notified_users.include?(only_assigned_user), "should not include users with the 'only_assigned' notification option"
966 assert !project.notified_users.include?(only_assigned_user), "should not include users with the 'only_assigned' notification option"
967 assert !project.notified_users.include?(only_owned_user), "should not include users with the 'only_owner' notification option"
967 assert !project.notified_users.include?(only_owned_user), "should not include users with the 'only_owner' notification option"
968 end
968 end
969
969
970 def test_override_roles_without_builtin_group_memberships
970 def test_override_roles_without_builtin_group_memberships
971 project = Project.generate!
971 project = Project.generate!
972 assert_equal [Role.anonymous], project.override_roles(Role.anonymous)
972 assert_equal [Role.anonymous], project.override_roles(Role.anonymous)
973 assert_equal [Role.non_member], project.override_roles(Role.non_member)
973 assert_equal [Role.non_member], project.override_roles(Role.non_member)
974 end
974 end
975
975
976 def test_css_classes
976 def test_css_classes
977 p = Project.new
977 p = Project.new
978 assert_kind_of String, p.css_classes
978 assert_kind_of String, p.css_classes
979 assert_not_include 'archived', p.css_classes.split
979 assert_not_include 'archived', p.css_classes.split
980 assert_not_include 'closed', p.css_classes.split
980 assert_not_include 'closed', p.css_classes.split
981 end
981 end
982
982
983 def test_css_classes_for_archived_project
983 def test_css_classes_for_archived_project
984 p = Project.new
984 p = Project.new
985 p.status = Project::STATUS_ARCHIVED
985 p.status = Project::STATUS_ARCHIVED
986 assert_include 'archived', p.css_classes.split
986 assert_include 'archived', p.css_classes.split
987 end
987 end
988
988
989 def test_css_classes_for_closed_project
989 def test_css_classes_for_closed_project
990 p = Project.new
990 p = Project.new
991 p.status = Project::STATUS_CLOSED
991 p.status = Project::STATUS_CLOSED
992 assert_include 'closed', p.css_classes.split
992 assert_include 'closed', p.css_classes.split
993 end
993 end
994
995 def test_combination_of_visible_and_uniq_scopes_in_case_anonymous_group_has_memberships_should_not_error
996 project = Project.find(1)
997 member = Member.create!(:project => project, :principal => Group.anonymous, :roles => [Role.generate!])
998 project.members << member
999 assert_nothing_raised do
1000 Project.uniq.visible.to_a
1001 end
1002 end
994 end
1003 end
General Comments 0
You need to be logged in to leave comments. Login now