##// END OF EJS Templates
Removing shoulda context....
Jean-Philippe Lang -
r11086:f4f3764686df
parent child
Show More
@@ -0,0 +1,316
1 # Redmine - project management software
2 # Copyright (C) 2006-2013 Jean-Philippe Lang
3 #
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
13 #
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
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
18 require File.expand_path('../../test_helper', __FILE__)
19
20 class ProjectCopyTest < ActiveSupport::TestCase
21 fixtures :projects, :trackers, :issue_statuses, :issues,
22 :journals, :journal_details,
23 :enumerations, :users, :issue_categories,
24 :projects_trackers,
25 :custom_fields,
26 :custom_fields_projects,
27 :custom_fields_trackers,
28 :custom_values,
29 :roles,
30 :member_roles,
31 :members,
32 :enabled_modules,
33 :workflows,
34 :versions,
35 :wikis, :wiki_pages, :wiki_contents, :wiki_content_versions,
36 :groups_users,
37 :boards, :messages,
38 :repositories,
39 :news, :comments,
40 :documents
41
42 def setup
43 ProjectCustomField.destroy_all
44 @source_project = Project.find(2)
45 @project = Project.new(:name => 'Copy Test', :identifier => 'copy-test')
46 @project.trackers = @source_project.trackers
47 @project.enabled_module_names = @source_project.enabled_modules.collect(&:name)
48 end
49
50 test "#copy should copy issues" do
51 @source_project.issues << Issue.generate!(:status => IssueStatus.find_by_name('Closed'),
52 :subject => "copy issue status",
53 :tracker_id => 1,
54 :assigned_to_id => 2,
55 :project_id => @source_project.id)
56 assert @project.valid?
57 assert @project.issues.empty?
58 assert @project.copy(@source_project)
59
60 assert_equal @source_project.issues.size, @project.issues.size
61 @project.issues.each do |issue|
62 assert issue.valid?
63 assert ! issue.assigned_to.blank?
64 assert_equal @project, issue.project
65 end
66
67 copied_issue = @project.issues.first(:conditions => {:subject => "copy issue status"})
68 assert copied_issue
69 assert copied_issue.status
70 assert_equal "Closed", copied_issue.status.name
71 end
72
73 test "#copy should copy issues assigned to a locked version" do
74 User.current = User.find(1)
75 assigned_version = Version.generate!(:name => "Assigned Issues")
76 @source_project.versions << assigned_version
77 Issue.generate!(:project => @source_project,
78 :fixed_version_id => assigned_version.id,
79 :subject => "copy issues assigned to a locked version")
80 assigned_version.update_attribute :status, 'locked'
81
82 assert @project.copy(@source_project)
83 @project.reload
84 copied_issue = @project.issues.first(:conditions => {:subject => "copy issues assigned to a locked version"})
85
86 assert copied_issue
87 assert copied_issue.fixed_version
88 assert_equal "Assigned Issues", copied_issue.fixed_version.name # Same name
89 assert_equal 'locked', copied_issue.fixed_version.status
90 end
91
92 test "#copy should change the new issues to use the copied version" do
93 User.current = User.find(1)
94 assigned_version = Version.generate!(:name => "Assigned Issues", :status => 'open')
95 @source_project.versions << assigned_version
96 assert_equal 3, @source_project.versions.size
97 Issue.generate!(:project => @source_project,
98 :fixed_version_id => assigned_version.id,
99 :subject => "change the new issues to use the copied version")
100
101 assert @project.copy(@source_project)
102 @project.reload
103 copied_issue = @project.issues.first(:conditions => {:subject => "change the new issues to use the copied version"})
104
105 assert copied_issue
106 assert copied_issue.fixed_version
107 assert_equal "Assigned Issues", copied_issue.fixed_version.name # Same name
108 assert_not_equal assigned_version.id, copied_issue.fixed_version.id # Different record
109 end
110
111 test "#copy should keep target shared versions from other project" do
112 assigned_version = Version.generate!(:name => "Assigned Issues", :status => 'open', :project_id => 1, :sharing => 'system')
113 issue = Issue.generate!(:project => @source_project,
114 :fixed_version => assigned_version,
115 :subject => "keep target shared versions")
116
117 assert @project.copy(@source_project)
118 @project.reload
119 copied_issue = @project.issues.first(:conditions => {:subject => "keep target shared versions"})
120
121 assert copied_issue
122 assert_equal assigned_version, copied_issue.fixed_version
123 end
124
125 test "#copy should copy issue relations" do
126 Setting.cross_project_issue_relations = '1'
127
128 second_issue = Issue.generate!(:status_id => 5,
129 :subject => "copy issue relation",
130 :tracker_id => 1,
131 :assigned_to_id => 2,
132 :project_id => @source_project.id)
133 source_relation = IssueRelation.create!(:issue_from => Issue.find(4),
134 :issue_to => second_issue,
135 :relation_type => "relates")
136 source_relation_cross_project = IssueRelation.create!(:issue_from => Issue.find(1),
137 :issue_to => second_issue,
138 :relation_type => "duplicates")
139
140 assert @project.copy(@source_project)
141 assert_equal @source_project.issues.count, @project.issues.count
142 copied_issue = @project.issues.find_by_subject("Issue on project 2") # Was #4
143 copied_second_issue = @project.issues.find_by_subject("copy issue relation")
144
145 # First issue with a relation on project
146 assert_equal 1, copied_issue.relations.size, "Relation not copied"
147 copied_relation = copied_issue.relations.first
148 assert_equal "relates", copied_relation.relation_type
149 assert_equal copied_second_issue.id, copied_relation.issue_to_id
150 assert_not_equal source_relation.id, copied_relation.id
151
152 # Second issue with a cross project relation
153 assert_equal 2, copied_second_issue.relations.size, "Relation not copied"
154 copied_relation = copied_second_issue.relations.select {|r| r.relation_type == 'duplicates'}.first
155 assert_equal "duplicates", copied_relation.relation_type
156 assert_equal 1, copied_relation.issue_from_id, "Cross project relation not kept"
157 assert_not_equal source_relation_cross_project.id, copied_relation.id
158 end
159
160 test "#copy should copy issue attachments" do
161 issue = Issue.generate!(:subject => "copy with attachment", :tracker_id => 1, :project_id => @source_project.id)
162 Attachment.create!(:container => issue, :file => uploaded_test_file("testfile.txt", "text/plain"), :author_id => 1)
163 @source_project.issues << issue
164 assert @project.copy(@source_project)
165
166 copied_issue = @project.issues.first(:conditions => {:subject => "copy with attachment"})
167 assert_not_nil copied_issue
168 assert_equal 1, copied_issue.attachments.count, "Attachment not copied"
169 assert_equal "testfile.txt", copied_issue.attachments.first.filename
170 end
171
172 test "#copy should copy memberships" do
173 assert @project.valid?
174 assert @project.members.empty?
175 assert @project.copy(@source_project)
176
177 assert_equal @source_project.memberships.size, @project.memberships.size
178 @project.memberships.each do |membership|
179 assert membership
180 assert_equal @project, membership.project
181 end
182 end
183
184 test "#copy should copy memberships with groups and additional roles" do
185 group = Group.create!(:lastname => "Copy group")
186 user = User.find(7)
187 group.users << user
188 # group role
189 Member.create!(:project_id => @source_project.id, :principal => group, :role_ids => [2])
190 member = Member.find_by_user_id_and_project_id(user.id, @source_project.id)
191 # additional role
192 member.role_ids = [1]
193
194 assert @project.copy(@source_project)
195 member = Member.find_by_user_id_and_project_id(user.id, @project.id)
196 assert_not_nil member
197 assert_equal [1, 2], member.role_ids.sort
198 end
199
200 test "#copy should copy project specific queries" do
201 assert @project.valid?
202 assert @project.queries.empty?
203 assert @project.copy(@source_project)
204
205 assert_equal @source_project.queries.size, @project.queries.size
206 @project.queries.each do |query|
207 assert query
208 assert_equal @project, query.project
209 end
210 assert_equal @source_project.queries.map(&:user_id).sort, @project.queries.map(&:user_id).sort
211 end
212
213 test "#copy should copy versions" do
214 @source_project.versions << Version.generate!
215 @source_project.versions << Version.generate!
216
217 assert @project.versions.empty?
218 assert @project.copy(@source_project)
219
220 assert_equal @source_project.versions.size, @project.versions.size
221 @project.versions.each do |version|
222 assert version
223 assert_equal @project, version.project
224 end
225 end
226
227 test "#copy should copy wiki" do
228 assert_difference 'Wiki.count' do
229 assert @project.copy(@source_project)
230 end
231
232 assert @project.wiki
233 assert_not_equal @source_project.wiki, @project.wiki
234 assert_equal "Start page", @project.wiki.start_page
235 end
236
237 test "#copy should copy wiki pages and content with hierarchy" do
238 assert_difference 'WikiPage.count', @source_project.wiki.pages.size do
239 assert @project.copy(@source_project)
240 end
241
242 assert @project.wiki
243 assert_equal @source_project.wiki.pages.size, @project.wiki.pages.size
244
245 @project.wiki.pages.each do |wiki_page|
246 assert wiki_page.content
247 assert !@source_project.wiki.pages.include?(wiki_page)
248 end
249
250 parent = @project.wiki.find_page('Parent_page')
251 child1 = @project.wiki.find_page('Child_page_1')
252 child2 = @project.wiki.find_page('Child_page_2')
253 assert_equal parent, child1.parent
254 assert_equal parent, child2.parent
255 end
256
257 test "#copy should copy issue categories" do
258 assert @project.copy(@source_project)
259
260 assert_equal 2, @project.issue_categories.size
261 @project.issue_categories.each do |issue_category|
262 assert !@source_project.issue_categories.include?(issue_category)
263 end
264 end
265
266 test "#copy should copy boards" do
267 assert @project.copy(@source_project)
268
269 assert_equal 1, @project.boards.size
270 @project.boards.each do |board|
271 assert !@source_project.boards.include?(board)
272 end
273 end
274
275 test "#copy should change the new issues to use the copied issue categories" do
276 issue = Issue.find(4)
277 issue.update_attribute(:category_id, 3)
278
279 assert @project.copy(@source_project)
280
281 @project.issues.each do |issue|
282 assert issue.category
283 assert_equal "Stock management", issue.category.name # Same name
284 assert_not_equal IssueCategory.find(3), issue.category # Different record
285 end
286 end
287
288 test "#copy should limit copy with :only option" do
289 assert @project.members.empty?
290 assert @project.issue_categories.empty?
291 assert @source_project.issues.any?
292
293 assert @project.copy(@source_project, :only => ['members', 'issue_categories'])
294
295 assert @project.members.any?
296 assert @project.issue_categories.any?
297 assert @project.issues.empty?
298 end
299
300 test "#copy should copy subtasks" do
301 source = Project.generate!(:tracker_ids => [1])
302 issue = Issue.generate_with_descendants!(:project => source)
303 project = Project.new(:name => 'Copy', :identifier => 'copy', :tracker_ids => [1])
304
305 assert_difference 'Project.count' do
306 assert_difference 'Issue.count', 1+issue.descendants.count do
307 assert project.copy(source.reload)
308 end
309 end
310 copy = Issue.where(:parent_id => nil).order("id DESC").first
311 assert_equal project, copy.project
312 assert_equal issue.descendants.count, copy.descendants.count
313 child_copy = copy.children.detect {|c| c.subject == 'Child1'}
314 assert child_copy.descendants.any?
315 end
316 end
@@ -1,1207 +1,904
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2013 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 require File.expand_path('../../test_helper', __FILE__)
19 19
20 20 class ProjectTest < ActiveSupport::TestCase
21 21 fixtures :projects, :trackers, :issue_statuses, :issues,
22 22 :journals, :journal_details,
23 23 :enumerations, :users, :issue_categories,
24 24 :projects_trackers,
25 25 :custom_fields,
26 26 :custom_fields_projects,
27 27 :custom_fields_trackers,
28 28 :custom_values,
29 29 :roles,
30 30 :member_roles,
31 31 :members,
32 32 :enabled_modules,
33 33 :workflows,
34 34 :versions,
35 35 :wikis, :wiki_pages, :wiki_contents, :wiki_content_versions,
36 36 :groups_users,
37 37 :boards, :messages,
38 38 :repositories,
39 39 :news, :comments,
40 40 :documents
41 41
42 42 def setup
43 43 @ecookbook = Project.find(1)
44 44 @ecookbook_sub1 = Project.find(3)
45 45 set_tmp_attachments_directory
46 46 User.current = nil
47 47 end
48 48
49 49 def test_truth
50 50 assert_kind_of Project, @ecookbook
51 51 assert_equal "eCookbook", @ecookbook.name
52 52 end
53 53
54 54 def test_default_attributes
55 55 with_settings :default_projects_public => '1' do
56 56 assert_equal true, Project.new.is_public
57 57 assert_equal false, Project.new(:is_public => false).is_public
58 58 end
59 59
60 60 with_settings :default_projects_public => '0' do
61 61 assert_equal false, Project.new.is_public
62 62 assert_equal true, Project.new(:is_public => true).is_public
63 63 end
64 64
65 65 with_settings :sequential_project_identifiers => '1' do
66 66 assert !Project.new.identifier.blank?
67 67 assert Project.new(:identifier => '').identifier.blank?
68 68 end
69 69
70 70 with_settings :sequential_project_identifiers => '0' do
71 71 assert Project.new.identifier.blank?
72 72 assert !Project.new(:identifier => 'test').blank?
73 73 end
74 74
75 75 with_settings :default_projects_modules => ['issue_tracking', 'repository'] do
76 76 assert_equal ['issue_tracking', 'repository'], Project.new.enabled_module_names
77 77 end
78 78
79 79 assert_equal Tracker.all.sort, Project.new.trackers.sort
80 80 assert_equal Tracker.find(1, 3).sort, Project.new(:tracker_ids => [1, 3]).trackers.sort
81 81 end
82 82
83 83 def test_update
84 84 assert_equal "eCookbook", @ecookbook.name
85 85 @ecookbook.name = "eCook"
86 86 assert @ecookbook.save, @ecookbook.errors.full_messages.join("; ")
87 87 @ecookbook.reload
88 88 assert_equal "eCook", @ecookbook.name
89 89 end
90 90
91 91 def test_validate_identifier
92 92 to_test = {"abc" => true,
93 93 "ab12" => true,
94 94 "ab-12" => true,
95 95 "ab_12" => true,
96 96 "12" => false,
97 97 "new" => false}
98 98
99 99 to_test.each do |identifier, valid|
100 100 p = Project.new
101 101 p.identifier = identifier
102 102 p.valid?
103 103 if valid
104 104 assert p.errors['identifier'].blank?, "identifier #{identifier} was not valid"
105 105 else
106 106 assert p.errors['identifier'].present?, "identifier #{identifier} was valid"
107 107 end
108 108 end
109 109 end
110 110
111 111 def test_identifier_should_not_be_frozen_for_a_new_project
112 112 assert_equal false, Project.new.identifier_frozen?
113 113 end
114 114
115 115 def test_identifier_should_not_be_frozen_for_a_saved_project_with_blank_identifier
116 116 Project.update_all(["identifier = ''"], "id = 1")
117 117
118 118 assert_equal false, Project.find(1).identifier_frozen?
119 119 end
120 120
121 121 def test_identifier_should_be_frozen_for_a_saved_project_with_valid_identifier
122 122 assert_equal true, Project.find(1).identifier_frozen?
123 123 end
124 124
125 125 def test_members_should_be_active_users
126 126 Project.all.each do |project|
127 127 assert_nil project.members.detect {|m| !(m.user.is_a?(User) && m.user.active?) }
128 128 end
129 129 end
130 130
131 131 def test_users_should_be_active_users
132 132 Project.all.each do |project|
133 133 assert_nil project.users.detect {|u| !(u.is_a?(User) && u.active?) }
134 134 end
135 135 end
136 136
137 137 def test_open_scope_on_issues_association
138 138 assert_kind_of Issue, Project.find(1).issues.open.first
139 139 end
140 140
141 141 def test_archive
142 142 user = @ecookbook.members.first.user
143 143 @ecookbook.archive
144 144 @ecookbook.reload
145 145
146 146 assert !@ecookbook.active?
147 147 assert @ecookbook.archived?
148 148 assert !user.projects.include?(@ecookbook)
149 149 # Subproject are also archived
150 150 assert !@ecookbook.children.empty?
151 151 assert @ecookbook.descendants.active.empty?
152 152 end
153 153
154 154 def test_archive_should_fail_if_versions_are_used_by_non_descendant_projects
155 155 # Assign an issue of a project to a version of a child project
156 156 Issue.find(4).update_attribute :fixed_version_id, 4
157 157
158 158 assert_no_difference "Project.count(:all, :conditions => 'status = #{Project::STATUS_ARCHIVED}')" do
159 159 assert_equal false, @ecookbook.archive
160 160 end
161 161 @ecookbook.reload
162 162 assert @ecookbook.active?
163 163 end
164 164
165 165 def test_unarchive
166 166 user = @ecookbook.members.first.user
167 167 @ecookbook.archive
168 168 # A subproject of an archived project can not be unarchived
169 169 assert !@ecookbook_sub1.unarchive
170 170
171 171 # Unarchive project
172 172 assert @ecookbook.unarchive
173 173 @ecookbook.reload
174 174 assert @ecookbook.active?
175 175 assert !@ecookbook.archived?
176 176 assert user.projects.include?(@ecookbook)
177 177 # Subproject can now be unarchived
178 178 @ecookbook_sub1.reload
179 179 assert @ecookbook_sub1.unarchive
180 180 end
181 181
182 182 def test_destroy
183 183 # 2 active members
184 184 assert_equal 2, @ecookbook.members.size
185 185 # and 1 is locked
186 186 assert_equal 3, Member.where('project_id = ?', @ecookbook.id).all.size
187 187 # some boards
188 188 assert @ecookbook.boards.any?
189 189
190 190 @ecookbook.destroy
191 191 # make sure that the project non longer exists
192 192 assert_raise(ActiveRecord::RecordNotFound) { Project.find(@ecookbook.id) }
193 193 # make sure related data was removed
194 194 assert_nil Member.first(:conditions => {:project_id => @ecookbook.id})
195 195 assert_nil Board.first(:conditions => {:project_id => @ecookbook.id})
196 196 assert_nil Issue.first(:conditions => {:project_id => @ecookbook.id})
197 197 end
198 198
199 199 def test_destroy_should_destroy_subtasks
200 200 issues = (0..2).to_a.map {Issue.create!(:project_id => 1, :tracker_id => 1, :author_id => 1, :subject => 'test')}
201 201 issues[0].update_attribute :parent_issue_id, issues[1].id
202 202 issues[2].update_attribute :parent_issue_id, issues[1].id
203 203 assert_equal 2, issues[1].children.count
204 204
205 205 assert_nothing_raised do
206 206 Project.find(1).destroy
207 207 end
208 208 assert Issue.find_all_by_id(issues.map(&:id)).empty?
209 209 end
210 210
211 211 def test_destroying_root_projects_should_clear_data
212 212 Project.roots.each do |root|
213 213 root.destroy
214 214 end
215 215
216 216 assert_equal 0, Project.count, "Projects were not deleted: #{Project.all.inspect}"
217 217 assert_equal 0, Member.count, "Members were not deleted: #{Member.all.inspect}"
218 218 assert_equal 0, MemberRole.count
219 219 assert_equal 0, Issue.count
220 220 assert_equal 0, Journal.count
221 221 assert_equal 0, JournalDetail.count
222 222 assert_equal 0, Attachment.count, "Attachments were not deleted: #{Attachment.all.inspect}"
223 223 assert_equal 0, EnabledModule.count
224 224 assert_equal 0, IssueCategory.count
225 225 assert_equal 0, IssueRelation.count
226 226 assert_equal 0, Board.count
227 227 assert_equal 0, Message.count
228 228 assert_equal 0, News.count
229 229 assert_equal 0, Query.count(:conditions => "project_id IS NOT NULL")
230 230 assert_equal 0, Repository.count
231 231 assert_equal 0, Changeset.count
232 232 assert_equal 0, Change.count
233 233 assert_equal 0, Comment.count
234 234 assert_equal 0, TimeEntry.count
235 235 assert_equal 0, Version.count
236 236 assert_equal 0, Watcher.count
237 237 assert_equal 0, Wiki.count
238 238 assert_equal 0, WikiPage.count
239 239 assert_equal 0, WikiContent.count
240 240 assert_equal 0, WikiContent::Version.count
241 241 assert_equal 0, Project.connection.select_all("SELECT * FROM projects_trackers").size
242 242 assert_equal 0, Project.connection.select_all("SELECT * FROM custom_fields_projects").size
243 243 assert_equal 0, CustomValue.count(:conditions => {:customized_type => ['Project', 'Issue', 'TimeEntry', 'Version']})
244 244 end
245 245
246 246 def test_move_an_orphan_project_to_a_root_project
247 247 sub = Project.find(2)
248 248 sub.set_parent! @ecookbook
249 249 assert_equal @ecookbook.id, sub.parent.id
250 250 @ecookbook.reload
251 251 assert_equal 4, @ecookbook.children.size
252 252 end
253 253
254 254 def test_move_an_orphan_project_to_a_subproject
255 255 sub = Project.find(2)
256 256 assert sub.set_parent!(@ecookbook_sub1)
257 257 end
258 258
259 259 def test_move_a_root_project_to_a_project
260 260 sub = @ecookbook
261 261 assert sub.set_parent!(Project.find(2))
262 262 end
263 263
264 264 def test_should_not_move_a_project_to_its_children
265 265 sub = @ecookbook
266 266 assert !(sub.set_parent!(Project.find(3)))
267 267 end
268 268
269 269 def test_set_parent_should_add_roots_in_alphabetical_order
270 270 ProjectCustomField.delete_all
271 271 Project.delete_all
272 272 Project.create!(:name => 'Project C', :identifier => 'project-c').set_parent!(nil)
273 273 Project.create!(:name => 'Project B', :identifier => 'project-b').set_parent!(nil)
274 274 Project.create!(:name => 'Project D', :identifier => 'project-d').set_parent!(nil)
275 275 Project.create!(:name => 'Project A', :identifier => 'project-a').set_parent!(nil)
276 276
277 277 assert_equal 4, Project.count
278 278 assert_equal Project.all.sort_by(&:name), Project.all.sort_by(&:lft)
279 279 end
280 280
281 281 def test_set_parent_should_add_children_in_alphabetical_order
282 282 ProjectCustomField.delete_all
283 283 parent = Project.create!(:name => 'Parent', :identifier => 'parent')
284 284 Project.create!(:name => 'Project C', :identifier => 'project-c').set_parent!(parent)
285 285 Project.create!(:name => 'Project B', :identifier => 'project-b').set_parent!(parent)
286 286 Project.create!(:name => 'Project D', :identifier => 'project-d').set_parent!(parent)
287 287 Project.create!(:name => 'Project A', :identifier => 'project-a').set_parent!(parent)
288 288
289 289 parent.reload
290 290 assert_equal 4, parent.children.size
291 291 assert_equal parent.children.all.sort_by(&:name), parent.children.all
292 292 end
293 293
294 294 def test_set_parent_should_update_issue_fixed_version_associations_when_a_fixed_version_is_moved_out_of_the_hierarchy
295 295 # Parent issue with a hierarchy project's fixed version
296 296 parent_issue = Issue.find(1)
297 297 parent_issue.update_attribute(:fixed_version_id, 4)
298 298 parent_issue.reload
299 299 assert_equal 4, parent_issue.fixed_version_id
300 300
301 301 # Should keep fixed versions for the issues
302 302 issue_with_local_fixed_version = Issue.find(5)
303 303 issue_with_local_fixed_version.update_attribute(:fixed_version_id, 4)
304 304 issue_with_local_fixed_version.reload
305 305 assert_equal 4, issue_with_local_fixed_version.fixed_version_id
306 306
307 307 # Local issue with hierarchy fixed_version
308 308 issue_with_hierarchy_fixed_version = Issue.find(13)
309 309 issue_with_hierarchy_fixed_version.update_attribute(:fixed_version_id, 6)
310 310 issue_with_hierarchy_fixed_version.reload
311 311 assert_equal 6, issue_with_hierarchy_fixed_version.fixed_version_id
312 312
313 313 # Move project out of the issue's hierarchy
314 314 moved_project = Project.find(3)
315 315 moved_project.set_parent!(Project.find(2))
316 316 parent_issue.reload
317 317 issue_with_local_fixed_version.reload
318 318 issue_with_hierarchy_fixed_version.reload
319 319
320 320 assert_equal 4, issue_with_local_fixed_version.fixed_version_id, "Fixed version was not keep on an issue local to the moved project"
321 321 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"
322 322 assert_equal nil, parent_issue.fixed_version_id, "Fixed version is still set after moving the Version out of the hierarchy for the issue."
323 323 end
324 324
325 325 def test_parent
326 326 p = Project.find(6).parent
327 327 assert p.is_a?(Project)
328 328 assert_equal 5, p.id
329 329 end
330 330
331 331 def test_ancestors
332 332 a = Project.find(6).ancestors
333 333 assert a.first.is_a?(Project)
334 334 assert_equal [1, 5], a.collect(&:id)
335 335 end
336 336
337 337 def test_root
338 338 r = Project.find(6).root
339 339 assert r.is_a?(Project)
340 340 assert_equal 1, r.id
341 341 end
342 342
343 343 def test_children
344 344 c = Project.find(1).children
345 345 assert c.first.is_a?(Project)
346 346 assert_equal [5, 3, 4], c.collect(&:id)
347 347 end
348 348
349 349 def test_descendants
350 350 d = Project.find(1).descendants
351 351 assert d.first.is_a?(Project)
352 352 assert_equal [5, 6, 3, 4], d.collect(&:id)
353 353 end
354 354
355 355 def test_allowed_parents_should_be_empty_for_non_member_user
356 356 Role.non_member.add_permission!(:add_project)
357 357 user = User.find(9)
358 358 assert user.memberships.empty?
359 359 User.current = user
360 360 assert Project.new.allowed_parents.compact.empty?
361 361 end
362 362
363 363 def test_allowed_parents_with_add_subprojects_permission
364 364 Role.find(1).remove_permission!(:add_project)
365 365 Role.find(1).add_permission!(:add_subprojects)
366 366 User.current = User.find(2)
367 367 # new project
368 368 assert !Project.new.allowed_parents.include?(nil)
369 369 assert Project.new.allowed_parents.include?(Project.find(1))
370 370 # existing root project
371 371 assert Project.find(1).allowed_parents.include?(nil)
372 372 # existing child
373 373 assert Project.find(3).allowed_parents.include?(Project.find(1))
374 374 assert !Project.find(3).allowed_parents.include?(nil)
375 375 end
376 376
377 377 def test_allowed_parents_with_add_project_permission
378 378 Role.find(1).add_permission!(:add_project)
379 379 Role.find(1).remove_permission!(:add_subprojects)
380 380 User.current = User.find(2)
381 381 # new project
382 382 assert Project.new.allowed_parents.include?(nil)
383 383 assert !Project.new.allowed_parents.include?(Project.find(1))
384 384 # existing root project
385 385 assert Project.find(1).allowed_parents.include?(nil)
386 386 # existing child
387 387 assert Project.find(3).allowed_parents.include?(Project.find(1))
388 388 assert Project.find(3).allowed_parents.include?(nil)
389 389 end
390 390
391 391 def test_allowed_parents_with_add_project_and_subprojects_permission
392 392 Role.find(1).add_permission!(:add_project)
393 393 Role.find(1).add_permission!(:add_subprojects)
394 394 User.current = User.find(2)
395 395 # new project
396 396 assert Project.new.allowed_parents.include?(nil)
397 397 assert Project.new.allowed_parents.include?(Project.find(1))
398 398 # existing root project
399 399 assert Project.find(1).allowed_parents.include?(nil)
400 400 # existing child
401 401 assert Project.find(3).allowed_parents.include?(Project.find(1))
402 402 assert Project.find(3).allowed_parents.include?(nil)
403 403 end
404 404
405 405 def test_users_by_role
406 406 users_by_role = Project.find(1).users_by_role
407 407 assert_kind_of Hash, users_by_role
408 408 role = Role.find(1)
409 409 assert_kind_of Array, users_by_role[role]
410 410 assert users_by_role[role].include?(User.find(2))
411 411 end
412 412
413 413 def test_rolled_up_trackers
414 414 parent = Project.find(1)
415 415 parent.trackers = Tracker.find([1,2])
416 416 child = parent.children.find(3)
417 417
418 418 assert_equal [1, 2], parent.tracker_ids
419 419 assert_equal [2, 3], child.trackers.collect(&:id)
420 420
421 421 assert_kind_of Tracker, parent.rolled_up_trackers.first
422 422 assert_equal Tracker.find(1), parent.rolled_up_trackers.first
423 423
424 424 assert_equal [1, 2, 3], parent.rolled_up_trackers.collect(&:id)
425 425 assert_equal [2, 3], child.rolled_up_trackers.collect(&:id)
426 426 end
427 427
428 428 def test_rolled_up_trackers_should_ignore_archived_subprojects
429 429 parent = Project.find(1)
430 430 parent.trackers = Tracker.find([1,2])
431 431 child = parent.children.find(3)
432 432 child.trackers = Tracker.find([1,3])
433 433 parent.children.each(&:archive)
434 434
435 435 assert_equal [1,2], parent.rolled_up_trackers.collect(&:id)
436 436 end
437 437
438 438 test "#rolled_up_versions should include the versions for the current project" do
439 439 project = Project.generate!
440 440 parent_version_1 = Version.generate!(:project => project)
441 441 parent_version_2 = Version.generate!(:project => project)
442 442 assert_same_elements [parent_version_1, parent_version_2], project.rolled_up_versions
443 443 end
444 444
445 445 test "#rolled_up_versions should include versions for a subproject" do
446 446 project = Project.generate!
447 447 parent_version_1 = Version.generate!(:project => project)
448 448 parent_version_2 = Version.generate!(:project => project)
449 449 subproject = Project.generate_with_parent!(project)
450 450 subproject_version = Version.generate!(:project => subproject)
451 451
452 452 assert_same_elements [
453 453 parent_version_1,
454 454 parent_version_2,
455 455 subproject_version
456 456 ], project.rolled_up_versions
457 457 end
458 458
459 459 test "#rolled_up_versions should include versions for a sub-subproject" do
460 460 project = Project.generate!
461 461 parent_version_1 = Version.generate!(:project => project)
462 462 parent_version_2 = Version.generate!(:project => project)
463 463 subproject = Project.generate_with_parent!(project)
464 464 sub_subproject = Project.generate_with_parent!(subproject)
465 465 sub_subproject_version = Version.generate!(:project => sub_subproject)
466 466 project.reload
467 467
468 468 assert_same_elements [
469 469 parent_version_1,
470 470 parent_version_2,
471 471 sub_subproject_version
472 472 ], project.rolled_up_versions
473 473 end
474 474
475 475 test "#rolled_up_versions should only check active projects" do
476 476 project = Project.generate!
477 477 parent_version_1 = Version.generate!(:project => project)
478 478 parent_version_2 = Version.generate!(:project => project)
479 479 subproject = Project.generate_with_parent!(project)
480 480 subproject_version = Version.generate!(:project => subproject)
481 481 assert subproject.archive
482 482 project.reload
483 483
484 484 assert !subproject.active?
485 485 assert_same_elements [parent_version_1, parent_version_2], project.rolled_up_versions
486 486 end
487 487
488 488 def test_shared_versions_none_sharing
489 489 p = Project.find(5)
490 490 v = Version.create!(:name => 'none_sharing', :project => p, :sharing => 'none')
491 491 assert p.shared_versions.include?(v)
492 492 assert !p.children.first.shared_versions.include?(v)
493 493 assert !p.root.shared_versions.include?(v)
494 494 assert !p.siblings.first.shared_versions.include?(v)
495 495 assert !p.root.siblings.first.shared_versions.include?(v)
496 496 end
497 497
498 498 def test_shared_versions_descendants_sharing
499 499 p = Project.find(5)
500 500 v = Version.create!(:name => 'descendants_sharing', :project => p, :sharing => 'descendants')
501 501 assert p.shared_versions.include?(v)
502 502 assert p.children.first.shared_versions.include?(v)
503 503 assert !p.root.shared_versions.include?(v)
504 504 assert !p.siblings.first.shared_versions.include?(v)
505 505 assert !p.root.siblings.first.shared_versions.include?(v)
506 506 end
507 507
508 508 def test_shared_versions_hierarchy_sharing
509 509 p = Project.find(5)
510 510 v = Version.create!(:name => 'hierarchy_sharing', :project => p, :sharing => 'hierarchy')
511 511 assert p.shared_versions.include?(v)
512 512 assert p.children.first.shared_versions.include?(v)
513 513 assert p.root.shared_versions.include?(v)
514 514 assert !p.siblings.first.shared_versions.include?(v)
515 515 assert !p.root.siblings.first.shared_versions.include?(v)
516 516 end
517 517
518 518 def test_shared_versions_tree_sharing
519 519 p = Project.find(5)
520 520 v = Version.create!(:name => 'tree_sharing', :project => p, :sharing => 'tree')
521 521 assert p.shared_versions.include?(v)
522 522 assert p.children.first.shared_versions.include?(v)
523 523 assert p.root.shared_versions.include?(v)
524 524 assert p.siblings.first.shared_versions.include?(v)
525 525 assert !p.root.siblings.first.shared_versions.include?(v)
526 526 end
527 527
528 528 def test_shared_versions_system_sharing
529 529 p = Project.find(5)
530 530 v = Version.create!(:name => 'system_sharing', :project => p, :sharing => 'system')
531 531 assert p.shared_versions.include?(v)
532 532 assert p.children.first.shared_versions.include?(v)
533 533 assert p.root.shared_versions.include?(v)
534 534 assert p.siblings.first.shared_versions.include?(v)
535 535 assert p.root.siblings.first.shared_versions.include?(v)
536 536 end
537 537
538 538 def test_shared_versions
539 539 parent = Project.find(1)
540 540 child = parent.children.find(3)
541 541 private_child = parent.children.find(5)
542 542
543 543 assert_equal [1,2,3], parent.version_ids.sort
544 544 assert_equal [4], child.version_ids
545 545 assert_equal [6], private_child.version_ids
546 546 assert_equal [7], Version.find_all_by_sharing('system').collect(&:id)
547 547
548 548 assert_equal 6, parent.shared_versions.size
549 549 parent.shared_versions.each do |version|
550 550 assert_kind_of Version, version
551 551 end
552 552
553 553 assert_equal [1,2,3,4,6,7], parent.shared_versions.collect(&:id).sort
554 554 end
555 555
556 556 def test_shared_versions_should_ignore_archived_subprojects
557 557 parent = Project.find(1)
558 558 child = parent.children.find(3)
559 559 child.archive
560 560 parent.reload
561 561
562 562 assert_equal [1,2,3], parent.version_ids.sort
563 563 assert_equal [4], child.version_ids
564 564 assert !parent.shared_versions.collect(&:id).include?(4)
565 565 end
566 566
567 567 def test_shared_versions_visible_to_user
568 568 user = User.find(3)
569 569 parent = Project.find(1)
570 570 child = parent.children.find(5)
571 571
572 572 assert_equal [1,2,3], parent.version_ids.sort
573 573 assert_equal [6], child.version_ids
574 574
575 575 versions = parent.shared_versions.visible(user)
576 576
577 577 assert_equal 4, versions.size
578 578 versions.each do |version|
579 579 assert_kind_of Version, version
580 580 end
581 581
582 582 assert !versions.collect(&:id).include?(6)
583 583 end
584 584
585 585 def test_shared_versions_for_new_project_should_include_system_shared_versions
586 586 p = Project.find(5)
587 587 v = Version.create!(:name => 'system_sharing', :project => p, :sharing => 'system')
588 588
589 589 assert_include v, Project.new.shared_versions
590 590 end
591 591
592 592 def test_next_identifier
593 593 ProjectCustomField.delete_all
594 594 Project.create!(:name => 'last', :identifier => 'p2008040')
595 595 assert_equal 'p2008041', Project.next_identifier
596 596 end
597 597
598 598 def test_next_identifier_first_project
599 599 Project.delete_all
600 600 assert_nil Project.next_identifier
601 601 end
602 602
603 603 def test_enabled_module_names
604 604 with_settings :default_projects_modules => ['issue_tracking', 'repository'] do
605 605 project = Project.new
606 606
607 607 project.enabled_module_names = %w(issue_tracking news)
608 608 assert_equal %w(issue_tracking news), project.enabled_module_names.sort
609 609 end
610 610 end
611 611
612 612 test "enabled_modules should define module by names and preserve ids" do
613 613 @project = Project.find(1)
614 614 # Remove one module
615 615 modules = @project.enabled_modules.slice(0..-2)
616 616 assert modules.any?
617 617 assert_difference 'EnabledModule.count', -1 do
618 618 @project.enabled_module_names = modules.collect(&:name)
619 619 end
620 620 @project.reload
621 621 # Ids should be preserved
622 622 assert_equal @project.enabled_module_ids.sort, modules.collect(&:id).sort
623 623 end
624 624
625 625 test "enabled_modules should enable a module" do
626 626 @project = Project.find(1)
627 627 @project.enabled_module_names = []
628 628 @project.reload
629 629 assert_equal [], @project.enabled_module_names
630 630 #with string
631 631 @project.enable_module!("issue_tracking")
632 632 assert_equal ["issue_tracking"], @project.enabled_module_names
633 633 #with symbol
634 634 @project.enable_module!(:gantt)
635 635 assert_equal ["issue_tracking", "gantt"], @project.enabled_module_names
636 636 #don't add a module twice
637 637 @project.enable_module!("issue_tracking")
638 638 assert_equal ["issue_tracking", "gantt"], @project.enabled_module_names
639 639 end
640 640
641 641 test "enabled_modules should disable a module" do
642 642 @project = Project.find(1)
643 643 #with string
644 644 assert @project.enabled_module_names.include?("issue_tracking")
645 645 @project.disable_module!("issue_tracking")
646 646 assert ! @project.reload.enabled_module_names.include?("issue_tracking")
647 647 #with symbol
648 648 assert @project.enabled_module_names.include?("gantt")
649 649 @project.disable_module!(:gantt)
650 650 assert ! @project.reload.enabled_module_names.include?("gantt")
651 651 #with EnabledModule object
652 652 first_module = @project.enabled_modules.first
653 653 @project.disable_module!(first_module)
654 654 assert ! @project.reload.enabled_module_names.include?(first_module.name)
655 655 end
656 656
657 657 def test_enabled_module_names_should_not_recreate_enabled_modules
658 658 project = Project.find(1)
659 659 # Remove one module
660 660 modules = project.enabled_modules.slice(0..-2)
661 661 assert modules.any?
662 662 assert_difference 'EnabledModule.count', -1 do
663 663 project.enabled_module_names = modules.collect(&:name)
664 664 end
665 665 project.reload
666 666 # Ids should be preserved
667 667 assert_equal project.enabled_module_ids.sort, modules.collect(&:id).sort
668 668 end
669 669
670 670 def test_copy_from_existing_project
671 671 source_project = Project.find(1)
672 672 copied_project = Project.copy_from(1)
673 673
674 674 assert copied_project
675 675 # Cleared attributes
676 676 assert copied_project.id.blank?
677 677 assert copied_project.name.blank?
678 678 assert copied_project.identifier.blank?
679 679
680 680 # Duplicated attributes
681 681 assert_equal source_project.description, copied_project.description
682 682 assert_equal source_project.enabled_modules, copied_project.enabled_modules
683 683 assert_equal source_project.trackers, copied_project.trackers
684 684
685 685 # Default attributes
686 686 assert_equal 1, copied_project.status
687 687 end
688 688
689 689 def test_activities_should_use_the_system_activities
690 690 project = Project.find(1)
691 691 assert_equal project.activities, TimeEntryActivity.where(:active => true).all
692 692 end
693 693
694 694
695 695 def test_activities_should_use_the_project_specific_activities
696 696 project = Project.find(1)
697 697 overridden_activity = TimeEntryActivity.new({:name => "Project", :project => project})
698 698 assert overridden_activity.save!
699 699
700 700 assert project.activities.include?(overridden_activity), "Project specific Activity not found"
701 701 end
702 702
703 703 def test_activities_should_not_include_the_inactive_project_specific_activities
704 704 project = Project.find(1)
705 705 overridden_activity = TimeEntryActivity.new({:name => "Project", :project => project, :parent => TimeEntryActivity.first, :active => false})
706 706 assert overridden_activity.save!
707 707
708 708 assert !project.activities.include?(overridden_activity), "Inactive Project specific Activity found"
709 709 end
710 710
711 711 def test_activities_should_not_include_project_specific_activities_from_other_projects
712 712 project = Project.find(1)
713 713 overridden_activity = TimeEntryActivity.new({:name => "Project", :project => Project.find(2)})
714 714 assert overridden_activity.save!
715 715
716 716 assert !project.activities.include?(overridden_activity), "Project specific Activity found on a different project"
717 717 end
718 718
719 719 def test_activities_should_handle_nils
720 720 overridden_activity = TimeEntryActivity.new({:name => "Project", :project => Project.find(1), :parent => TimeEntryActivity.first})
721 721 TimeEntryActivity.delete_all
722 722
723 723 # No activities
724 724 project = Project.find(1)
725 725 assert project.activities.empty?
726 726
727 727 # No system, one overridden
728 728 assert overridden_activity.save!
729 729 project.reload
730 730 assert_equal [overridden_activity], project.activities
731 731 end
732 732
733 733 def test_activities_should_override_system_activities_with_project_activities
734 734 project = Project.find(1)
735 735 parent_activity = TimeEntryActivity.first
736 736 overridden_activity = TimeEntryActivity.new({:name => "Project", :project => project, :parent => parent_activity})
737 737 assert overridden_activity.save!
738 738
739 739 assert project.activities.include?(overridden_activity), "Project specific Activity not found"
740 740 assert !project.activities.include?(parent_activity), "System Activity found when it should have been overridden"
741 741 end
742 742
743 743 def test_activities_should_include_inactive_activities_if_specified
744 744 project = Project.find(1)
745 745 overridden_activity = TimeEntryActivity.new({:name => "Project", :project => project, :parent => TimeEntryActivity.first, :active => false})
746 746 assert overridden_activity.save!
747 747
748 748 assert project.activities(true).include?(overridden_activity), "Inactive Project specific Activity not found"
749 749 end
750 750
751 751 test 'activities should not include active System activities if the project has an override that is inactive' do
752 752 project = Project.find(1)
753 753 system_activity = TimeEntryActivity.find_by_name('Design')
754 754 assert system_activity.active?
755 755 overridden_activity = TimeEntryActivity.create!(:name => "Project", :project => project, :parent => system_activity, :active => false)
756 756 assert overridden_activity.save!
757 757
758 758 assert !project.activities.include?(overridden_activity), "Inactive Project specific Activity not found"
759 759 assert !project.activities.include?(system_activity), "System activity found when the project has an inactive override"
760 760 end
761 761
762 762 def test_close_completed_versions
763 763 Version.update_all("status = 'open'")
764 764 project = Project.find(1)
765 765 assert_not_nil project.versions.detect {|v| v.completed? && v.status == 'open'}
766 766 assert_not_nil project.versions.detect {|v| !v.completed? && v.status == 'open'}
767 767 project.close_completed_versions
768 768 project.reload
769 769 assert_nil project.versions.detect {|v| v.completed? && v.status != 'closed'}
770 770 assert_not_nil project.versions.detect {|v| !v.completed? && v.status == 'open'}
771 771 end
772 772
773 context "Project#copy" do
774 setup do
775 ProjectCustomField.destroy_all # Custom values are a mess to isolate in tests
776 Project.destroy_all :identifier => "copy-test"
777 @source_project = Project.find(2)
778 @project = Project.new(:name => 'Copy Test', :identifier => 'copy-test')
779 @project.trackers = @source_project.trackers
780 @project.enabled_module_names = @source_project.enabled_modules.collect(&:name)
781 end
782
783 should "copy issues" do
784 @source_project.issues << Issue.generate!(:status => IssueStatus.find_by_name('Closed'),
785 :subject => "copy issue status",
786 :tracker_id => 1,
787 :assigned_to_id => 2,
788 :project_id => @source_project.id)
789 assert @project.valid?
790 assert @project.issues.empty?
791 assert @project.copy(@source_project)
792
793 assert_equal @source_project.issues.size, @project.issues.size
794 @project.issues.each do |issue|
795 assert issue.valid?
796 assert ! issue.assigned_to.blank?
797 assert_equal @project, issue.project
798 end
799
800 copied_issue = @project.issues.first(:conditions => {:subject => "copy issue status"})
801 assert copied_issue
802 assert copied_issue.status
803 assert_equal "Closed", copied_issue.status.name
804 end
805
806 should "copy issues assigned to a locked version" do
807 User.current = User.find(1)
808 assigned_version = Version.generate!(:name => "Assigned Issues")
809 @source_project.versions << assigned_version
810 Issue.generate!(:project => @source_project,
811 :fixed_version_id => assigned_version.id,
812 :subject => "copy issues assigned to a locked version")
813 assigned_version.update_attribute :status, 'locked'
814
815 assert @project.copy(@source_project)
816 @project.reload
817 copied_issue = @project.issues.first(:conditions => {:subject => "copy issues assigned to a locked version"})
818
819 assert copied_issue
820 assert copied_issue.fixed_version
821 assert_equal "Assigned Issues", copied_issue.fixed_version.name # Same name
822 assert_equal 'locked', copied_issue.fixed_version.status
823 end
824
825 should "change the new issues to use the copied version" do
826 User.current = User.find(1)
827 assigned_version = Version.generate!(:name => "Assigned Issues", :status => 'open')
828 @source_project.versions << assigned_version
829 assert_equal 3, @source_project.versions.size
830 Issue.generate!(:project => @source_project,
831 :fixed_version_id => assigned_version.id,
832 :subject => "change the new issues to use the copied version")
833
834 assert @project.copy(@source_project)
835 @project.reload
836 copied_issue = @project.issues.first(:conditions => {:subject => "change the new issues to use the copied version"})
837
838 assert copied_issue
839 assert copied_issue.fixed_version
840 assert_equal "Assigned Issues", copied_issue.fixed_version.name # Same name
841 assert_not_equal assigned_version.id, copied_issue.fixed_version.id # Different record
842 end
843
844 should "keep target shared versions from other project" do
845 assigned_version = Version.generate!(:name => "Assigned Issues", :status => 'open', :project_id => 1, :sharing => 'system')
846 issue = Issue.generate!(:project => @source_project,
847 :fixed_version => assigned_version,
848 :subject => "keep target shared versions")
849
850 assert @project.copy(@source_project)
851 @project.reload
852 copied_issue = @project.issues.first(:conditions => {:subject => "keep target shared versions"})
853
854 assert copied_issue
855 assert_equal assigned_version, copied_issue.fixed_version
856 end
857
858 should "copy issue relations" do
859 Setting.cross_project_issue_relations = '1'
860
861 second_issue = Issue.generate!(:status_id => 5,
862 :subject => "copy issue relation",
863 :tracker_id => 1,
864 :assigned_to_id => 2,
865 :project_id => @source_project.id)
866 source_relation = IssueRelation.create!(:issue_from => Issue.find(4),
867 :issue_to => second_issue,
868 :relation_type => "relates")
869 source_relation_cross_project = IssueRelation.create!(:issue_from => Issue.find(1),
870 :issue_to => second_issue,
871 :relation_type => "duplicates")
872
873 assert @project.copy(@source_project)
874 assert_equal @source_project.issues.count, @project.issues.count
875 copied_issue = @project.issues.find_by_subject("Issue on project 2") # Was #4
876 copied_second_issue = @project.issues.find_by_subject("copy issue relation")
877
878 # First issue with a relation on project
879 assert_equal 1, copied_issue.relations.size, "Relation not copied"
880 copied_relation = copied_issue.relations.first
881 assert_equal "relates", copied_relation.relation_type
882 assert_equal copied_second_issue.id, copied_relation.issue_to_id
883 assert_not_equal source_relation.id, copied_relation.id
884
885 # Second issue with a cross project relation
886 assert_equal 2, copied_second_issue.relations.size, "Relation not copied"
887 copied_relation = copied_second_issue.relations.select {|r| r.relation_type == 'duplicates'}.first
888 assert_equal "duplicates", copied_relation.relation_type
889 assert_equal 1, copied_relation.issue_from_id, "Cross project relation not kept"
890 assert_not_equal source_relation_cross_project.id, copied_relation.id
891 end
892
893 should "copy issue attachments" do
894 issue = Issue.generate!(:subject => "copy with attachment", :tracker_id => 1, :project_id => @source_project.id)
895 Attachment.create!(:container => issue, :file => uploaded_test_file("testfile.txt", "text/plain"), :author_id => 1)
896 @source_project.issues << issue
897 assert @project.copy(@source_project)
898
899 copied_issue = @project.issues.first(:conditions => {:subject => "copy with attachment"})
900 assert_not_nil copied_issue
901 assert_equal 1, copied_issue.attachments.count, "Attachment not copied"
902 assert_equal "testfile.txt", copied_issue.attachments.first.filename
903 end
904
905 should "copy memberships" do
906 assert @project.valid?
907 assert @project.members.empty?
908 assert @project.copy(@source_project)
909
910 assert_equal @source_project.memberships.size, @project.memberships.size
911 @project.memberships.each do |membership|
912 assert membership
913 assert_equal @project, membership.project
914 end
915 end
916
917 should "copy memberships with groups and additional roles" do
918 group = Group.create!(:lastname => "Copy group")
919 user = User.find(7)
920 group.users << user
921 # group role
922 Member.create!(:project_id => @source_project.id, :principal => group, :role_ids => [2])
923 member = Member.find_by_user_id_and_project_id(user.id, @source_project.id)
924 # additional role
925 member.role_ids = [1]
926
927 assert @project.copy(@source_project)
928 member = Member.find_by_user_id_and_project_id(user.id, @project.id)
929 assert_not_nil member
930 assert_equal [1, 2], member.role_ids.sort
931 end
932
933 should "copy project specific queries" do
934 assert @project.valid?
935 assert @project.queries.empty?
936 assert @project.copy(@source_project)
937
938 assert_equal @source_project.queries.size, @project.queries.size
939 @project.queries.each do |query|
940 assert query
941 assert_equal @project, query.project
942 end
943 assert_equal @source_project.queries.map(&:user_id).sort, @project.queries.map(&:user_id).sort
944 end
945
946 should "copy versions" do
947 @source_project.versions << Version.generate!
948 @source_project.versions << Version.generate!
949
950 assert @project.versions.empty?
951 assert @project.copy(@source_project)
952
953 assert_equal @source_project.versions.size, @project.versions.size
954 @project.versions.each do |version|
955 assert version
956 assert_equal @project, version.project
957 end
958 end
959
960 should "copy wiki" do
961 assert_difference 'Wiki.count' do
962 assert @project.copy(@source_project)
963 end
964
965 assert @project.wiki
966 assert_not_equal @source_project.wiki, @project.wiki
967 assert_equal "Start page", @project.wiki.start_page
968 end
969
970 should "copy wiki pages and content with hierarchy" do
971 assert_difference 'WikiPage.count', @source_project.wiki.pages.size do
972 assert @project.copy(@source_project)
973 end
974
975 assert @project.wiki
976 assert_equal @source_project.wiki.pages.size, @project.wiki.pages.size
977
978 @project.wiki.pages.each do |wiki_page|
979 assert wiki_page.content
980 assert !@source_project.wiki.pages.include?(wiki_page)
981 end
982
983 parent = @project.wiki.find_page('Parent_page')
984 child1 = @project.wiki.find_page('Child_page_1')
985 child2 = @project.wiki.find_page('Child_page_2')
986 assert_equal parent, child1.parent
987 assert_equal parent, child2.parent
988 end
989
990 should "copy issue categories" do
991 assert @project.copy(@source_project)
992
993 assert_equal 2, @project.issue_categories.size
994 @project.issue_categories.each do |issue_category|
995 assert !@source_project.issue_categories.include?(issue_category)
996 end
997 end
998
999 should "copy boards" do
1000 assert @project.copy(@source_project)
1001
1002 assert_equal 1, @project.boards.size
1003 @project.boards.each do |board|
1004 assert !@source_project.boards.include?(board)
1005 end
1006 end
1007
1008 should "change the new issues to use the copied issue categories" do
1009 issue = Issue.find(4)
1010 issue.update_attribute(:category_id, 3)
1011
1012 assert @project.copy(@source_project)
1013
1014 @project.issues.each do |issue|
1015 assert issue.category
1016 assert_equal "Stock management", issue.category.name # Same name
1017 assert_not_equal IssueCategory.find(3), issue.category # Different record
1018 end
1019 end
1020
1021 should "limit copy with :only option" do
1022 assert @project.members.empty?
1023 assert @project.issue_categories.empty?
1024 assert @source_project.issues.any?
1025
1026 assert @project.copy(@source_project, :only => ['members', 'issue_categories'])
1027
1028 assert @project.members.any?
1029 assert @project.issue_categories.any?
1030 assert @project.issues.empty?
1031 end
1032 end
1033
1034 def test_copy_should_copy_subtasks
1035 source = Project.generate!(:tracker_ids => [1])
1036 issue = Issue.generate_with_descendants!(:project => source)
1037 project = Project.new(:name => 'Copy', :identifier => 'copy', :tracker_ids => [1])
1038
1039 assert_difference 'Project.count' do
1040 assert_difference 'Issue.count', 1+issue.descendants.count do
1041 assert project.copy(source.reload)
1042 end
1043 end
1044 copy = Issue.where(:parent_id => nil).order("id DESC").first
1045 assert_equal project, copy.project
1046 assert_equal issue.descendants.count, copy.descendants.count
1047 child_copy = copy.children.detect {|c| c.subject == 'Child1'}
1048 assert child_copy.descendants.any?
773 test "#start_date should be nil if there are no issues on the project" do
774 project = Project.generate!
775 assert_nil project.start_date
1049 776 end
1050 777
1051 context "#start_date" do
1052 setup do
1053 ProjectCustomField.destroy_all # Custom values are a mess to isolate in tests
1054 @project = Project.generate!(:identifier => 'test0')
1055 @project.trackers << Tracker.generate!
1056 end
778 test "#start_date should be nil when issues have no start date" do
779 project = Project.generate!
780 project.trackers << Tracker.generate!
781 early = 7.days.ago.to_date
782 Issue.generate!(:project => project, :start_date => nil)
1057 783
1058 should "be nil if there are no issues on the project" do
1059 assert_nil @project.start_date
784 assert_nil project.start_date
1060 785 end
1061 786
1062 should "be tested when issues have no start date"
1063
1064 should "be the earliest start date of it's issues" do
787 test "#start_date should be the earliest start date of it's issues" do
788 project = Project.generate!
789 project.trackers << Tracker.generate!
1065 790 early = 7.days.ago.to_date
1066 Issue.generate!(:project => @project, :start_date => Date.today)
1067 Issue.generate!(:project => @project, :start_date => early)
791 Issue.generate!(:project => project, :start_date => Date.today)
792 Issue.generate!(:project => project, :start_date => early)
1068 793
1069 assert_equal early, @project.start_date
794 assert_equal early, project.start_date
1070 795 end
1071 796
797 test "#due_date should be nil if there are no issues on the project" do
798 project = Project.generate!
799 assert_nil project.due_date
1072 800 end
1073 801
1074 context "#due_date" do
1075 setup do
1076 ProjectCustomField.destroy_all # Custom values are a mess to isolate in tests
1077 @project = Project.generate!(:identifier => 'test0')
1078 @project.trackers << Tracker.generate!
1079 end
802 test "#due_date should be nil if there are no issues with due dates" do
803 project = Project.generate!
804 project.trackers << Tracker.generate!
805 Issue.generate!(:project => project, :due_date => nil)
1080 806
1081 should "be nil if there are no issues on the project" do
1082 assert_nil @project.due_date
807 assert_nil project.due_date
1083 808 end
1084 809
1085 should "be tested when issues have no due date"
1086
1087 should "be the latest due date of it's issues" do
810 test "#due_date should be the latest due date of it's issues" do
811 project = Project.generate!
812 project.trackers << Tracker.generate!
1088 813 future = 7.days.from_now.to_date
1089 Issue.generate!(:project => @project, :due_date => future)
1090 Issue.generate!(:project => @project, :due_date => Date.today)
814 Issue.generate!(:project => project, :due_date => future)
815 Issue.generate!(:project => project, :due_date => Date.today)
1091 816
1092 assert_equal future, @project.due_date
817 assert_equal future, project.due_date
1093 818 end
1094 819
1095 should "be the latest due date of it's versions" do
820 test "#due_date should be the latest due date of it's versions" do
821 project = Project.generate!
1096 822 future = 7.days.from_now.to_date
1097 @project.versions << Version.generate!(:effective_date => future)
1098 @project.versions << Version.generate!(:effective_date => Date.today)
1099
1100
1101 assert_equal future, @project.due_date
823 project.versions << Version.generate!(:effective_date => future)
824 project.versions << Version.generate!(:effective_date => Date.today)
1102 825
826 assert_equal future, project.due_date
1103 827 end
1104 828
1105 should "pick the latest date from it's issues and versions" do
829 test "#due_date should pick the latest date from it's issues and versions" do
830 project = Project.generate!
831 project.trackers << Tracker.generate!
1106 832 future = 7.days.from_now.to_date
1107 833 far_future = 14.days.from_now.to_date
1108 Issue.generate!(:project => @project, :due_date => far_future)
1109 @project.versions << Version.generate!(:effective_date => future)
1110
1111 assert_equal far_future, @project.due_date
1112 end
834 Issue.generate!(:project => project, :due_date => far_future)
835 project.versions << Version.generate!(:effective_date => future)
1113 836
837 assert_equal far_future, project.due_date
1114 838 end
1115 839
1116 context "Project#completed_percent" do
1117 setup do
1118 ProjectCustomField.destroy_all # Custom values are a mess to isolate in tests
1119 @project = Project.generate!(:identifier => 'test0')
1120 @project.trackers << Tracker.generate!
1121 end
1122
1123 context "no versions" do
1124 should "be 100" do
1125 assert_equal 100, @project.completed_percent
1126 end
840 test "#completed_percent with no versions should be 100" do
841 project = Project.generate!
842 assert_equal 100, project.completed_percent
1127 843 end
1128 844
1129 context "with versions" do
1130 should "return 0 if the versions have no issues" do
1131 Version.generate!(:project => @project)
1132 Version.generate!(:project => @project)
845 test "#completed_percent with versions should return 0 if the versions have no issues" do
846 project = Project.generate!
847 Version.generate!(:project => project)
848 Version.generate!(:project => project)
1133 849
1134 assert_equal 0, @project.completed_percent
850 assert_equal 0, project.completed_percent
1135 851 end
1136 852
1137 should "return 100 if the version has only closed issues" do
1138 v1 = Version.generate!(:project => @project)
1139 Issue.generate!(:project => @project, :status => IssueStatus.find_by_name('Closed'), :fixed_version => v1)
1140 v2 = Version.generate!(:project => @project)
1141 Issue.generate!(:project => @project, :status => IssueStatus.find_by_name('Closed'), :fixed_version => v2)
853 test "#completed_percent with versions should return 100 if the version has only closed issues" do
854 project = Project.generate!
855 project.trackers << Tracker.generate!
856 v1 = Version.generate!(:project => project)
857 Issue.generate!(:project => project, :status => IssueStatus.find_by_name('Closed'), :fixed_version => v1)
858 v2 = Version.generate!(:project => project)
859 Issue.generate!(:project => project, :status => IssueStatus.find_by_name('Closed'), :fixed_version => v2)
1142 860
1143 assert_equal 100, @project.completed_percent
861 assert_equal 100, project.completed_percent
1144 862 end
1145 863
1146 should "return the averaged completed percent of the versions (not weighted)" do
1147 v1 = Version.generate!(:project => @project)
1148 Issue.generate!(:project => @project, :status => IssueStatus.find_by_name('New'), :estimated_hours => 10, :done_ratio => 50, :fixed_version => v1)
1149 v2 = Version.generate!(:project => @project)
1150 Issue.generate!(:project => @project, :status => IssueStatus.find_by_name('New'), :estimated_hours => 10, :done_ratio => 50, :fixed_version => v2)
1151
1152 assert_equal 50, @project.completed_percent
1153 end
864 test "#completed_percent with versions should return the averaged completed percent of the versions (not weighted)" do
865 project = Project.generate!
866 project.trackers << Tracker.generate!
867 v1 = Version.generate!(:project => project)
868 Issue.generate!(:project => project, :status => IssueStatus.find_by_name('New'), :estimated_hours => 10, :done_ratio => 50, :fixed_version => v1)
869 v2 = Version.generate!(:project => project)
870 Issue.generate!(:project => project, :status => IssueStatus.find_by_name('New'), :estimated_hours => 10, :done_ratio => 50, :fixed_version => v2)
1154 871
872 assert_equal 50, project.completed_percent
1155 873 end
1156 end
1157
1158 context "#notified_users" do
1159 setup do
1160 @project = Project.generate!
1161 @role = Role.generate!
1162 874
1163 @user_with_membership_notification = User.generate!(:mail_notification => 'selected')
1164 Member.create!(:project => @project, :roles => [@role], :principal => @user_with_membership_notification, :mail_notification => true)
1165
1166 @all_events_user = User.generate!(:mail_notification => 'all')
1167 Member.create!(:project => @project, :roles => [@role], :principal => @all_events_user)
875 test "#notified_users" do
876 project = Project.generate!
877 role = Role.generate!
1168 878
1169 @no_events_user = User.generate!(:mail_notification => 'none')
1170 Member.create!(:project => @project, :roles => [@role], :principal => @no_events_user)
879 user_with_membership_notification = User.generate!(:mail_notification => 'selected')
880 Member.create!(:project => project, :roles => [role], :principal => user_with_membership_notification, :mail_notification => true)
1171 881
1172 @only_my_events_user = User.generate!(:mail_notification => 'only_my_events')
1173 Member.create!(:project => @project, :roles => [@role], :principal => @only_my_events_user)
882 all_events_user = User.generate!(:mail_notification => 'all')
883 Member.create!(:project => project, :roles => [role], :principal => all_events_user)
1174 884
1175 @only_assigned_user = User.generate!(:mail_notification => 'only_assigned')
1176 Member.create!(:project => @project, :roles => [@role], :principal => @only_assigned_user)
885 no_events_user = User.generate!(:mail_notification => 'none')
886 Member.create!(:project => project, :roles => [role], :principal => no_events_user)
1177 887
1178 @only_owned_user = User.generate!(:mail_notification => 'only_owner')
1179 Member.create!(:project => @project, :roles => [@role], :principal => @only_owned_user)
1180 end
888 only_my_events_user = User.generate!(:mail_notification => 'only_my_events')
889 Member.create!(:project => project, :roles => [role], :principal => only_my_events_user)
1181 890
1182 should "include members with a mail notification" do
1183 assert @project.notified_users.include?(@user_with_membership_notification)
1184 end
891 only_assigned_user = User.generate!(:mail_notification => 'only_assigned')
892 Member.create!(:project => project, :roles => [role], :principal => only_assigned_user)
1185 893
1186 should "include users with the 'all' notification option" do
1187 assert @project.notified_users.include?(@all_events_user)
1188 end
1189
1190 should "not include users with the 'none' notification option" do
1191 assert !@project.notified_users.include?(@no_events_user)
1192 end
894 only_owned_user = User.generate!(:mail_notification => 'only_owner')
895 Member.create!(:project => project, :roles => [role], :principal => only_owned_user)
1193 896
1194 should "not include users with the 'only_my_events' notification option" do
1195 assert !@project.notified_users.include?(@only_my_events_user)
897 assert project.notified_users.include?(user_with_membership_notification), "should include members with a mail notification"
898 assert project.notified_users.include?(all_events_user), "should include users with the 'all' notification option"
899 assert !project.notified_users.include?(no_events_user), "should not include users with the 'none' notification option"
900 assert !project.notified_users.include?(only_my_events_user), "should not include users with the 'only_my_events' notification option"
901 assert !project.notified_users.include?(only_assigned_user), "should not include users with the 'only_assigned' notification option"
902 assert !project.notified_users.include?(only_owned_user), "should not include users with the 'only_owner' notification option"
1196 903 end
1197
1198 should "not include users with the 'only_assigned' notification option" do
1199 assert !@project.notified_users.include?(@only_assigned_user)
1200 end
1201
1202 should "not include users with the 'only_owner' notification option" do
1203 assert !@project.notified_users.include?(@only_owned_user)
1204 end
1205 end
1206
1207 904 end
General Comments 0
You need to be logged in to leave comments. Login now