##// END OF EJS Templates
Add option to set a new version as default directly from New Version page (#24011)....
Jean-Philippe Lang -
r15540:eb023bdcce2b
parent child
Show More
@@ -1,336 +1,362
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2016 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 class Version < ActiveRecord::Base
19 19 include Redmine::SafeAttributes
20 20
21 21 after_update :update_issues_from_sharing_change
22 after_save :update_default_project_version
22 23 before_destroy :nullify_projects_default_version
23 24
24 25 belongs_to :project
25 26 has_many :fixed_issues, :class_name => 'Issue', :foreign_key => 'fixed_version_id', :dependent => :nullify
26 27 acts_as_customizable
27 28 acts_as_attachable :view_permission => :view_files,
28 29 :edit_permission => :manage_files,
29 30 :delete_permission => :manage_files
30 31
31 32 VERSION_STATUSES = %w(open locked closed)
32 33 VERSION_SHARINGS = %w(none descendants hierarchy tree system)
33 34
34 35 validates_presence_of :name
35 36 validates_uniqueness_of :name, :scope => [:project_id]
36 37 validates_length_of :name, :maximum => 60
37 38 validates_length_of :description, :maximum => 255
38 39 validates :effective_date, :date => true
39 40 validates_inclusion_of :status, :in => VERSION_STATUSES
40 41 validates_inclusion_of :sharing, :in => VERSION_SHARINGS
41 42 attr_protected :id
42 43
43 44 scope :named, lambda {|arg| where("LOWER(#{table_name}.name) = LOWER(?)", arg.to_s.strip)}
44 45 scope :like, lambda {|arg|
45 46 if arg.present?
46 47 pattern = "%#{arg.to_s.strip}%"
47 48 where("LOWER(#{Version.table_name}.name) LIKE :p", :p => pattern)
48 49 end
49 50 }
50 51 scope :open, lambda { where(:status => 'open') }
51 52 scope :status, lambda {|status|
52 53 if status.present?
53 54 where(:status => status.to_s)
54 55 end
55 56 }
56 57 scope :visible, lambda {|*args|
57 58 joins(:project).
58 59 where(Project.allowed_to_condition(args.first || User.current, :view_issues))
59 60 }
60 61
61 62 safe_attributes 'name',
62 63 'description',
63 64 'effective_date',
64 65 'due_date',
65 66 'wiki_page_title',
66 67 'status',
67 68 'sharing',
69 'default_project_version',
68 70 'custom_field_values',
69 71 'custom_fields'
70 72
71 73 # Returns true if +user+ or current user is allowed to view the version
72 74 def visible?(user=User.current)
73 75 user.allowed_to?(:view_issues, self.project)
74 76 end
75 77
76 78 # Version files have same visibility as project files
77 79 def attachments_visible?(*args)
78 80 project.present? && project.attachments_visible?(*args)
79 81 end
80 82
81 83 def attachments_deletable?(usr=User.current)
82 84 project.present? && project.attachments_deletable?(usr)
83 85 end
84 86
87 alias :base_reload :reload
88 def reload(*args)
89 @default_project_version = nil
90 base_reload(*args)
91 end
92
85 93 def start_date
86 94 @start_date ||= fixed_issues.minimum('start_date')
87 95 end
88 96
89 97 def due_date
90 98 effective_date
91 99 end
92 100
93 101 def due_date=(arg)
94 102 self.effective_date=(arg)
95 103 end
96 104
97 105 # Returns the total estimated time for this version
98 106 # (sum of leaves estimated_hours)
99 107 def estimated_hours
100 108 @estimated_hours ||= fixed_issues.sum(:estimated_hours).to_f
101 109 end
102 110
103 111 # Returns the total reported time for this version
104 112 def spent_hours
105 113 @spent_hours ||= TimeEntry.joins(:issue).where("#{Issue.table_name}.fixed_version_id = ?", id).sum(:hours).to_f
106 114 end
107 115
108 116 def closed?
109 117 status == 'closed'
110 118 end
111 119
112 120 def open?
113 121 status == 'open'
114 122 end
115 123
116 124 # Returns true if the version is completed: closed or due date reached and no open issues
117 125 def completed?
118 126 closed? || (effective_date && (effective_date < User.current.today) && (open_issues_count == 0))
119 127 end
120 128
121 129 def behind_schedule?
122 130 if completed_percent == 100
123 131 return false
124 132 elsif due_date && start_date
125 133 done_date = start_date + ((due_date - start_date+1)* completed_percent/100).floor
126 134 return done_date <= User.current.today
127 135 else
128 136 false # No issues so it's not late
129 137 end
130 138 end
131 139
132 140 # Returns the completion percentage of this version based on the amount of open/closed issues
133 141 # and the time spent on the open issues.
134 142 def completed_percent
135 143 if issues_count == 0
136 144 0
137 145 elsif open_issues_count == 0
138 146 100
139 147 else
140 148 issues_progress(false) + issues_progress(true)
141 149 end
142 150 end
143 151
144 152 # Returns the percentage of issues that have been marked as 'closed'.
145 153 def closed_percent
146 154 if issues_count == 0
147 155 0
148 156 else
149 157 issues_progress(false)
150 158 end
151 159 end
152 160
153 161 # Returns true if the version is overdue: due date reached and some open issues
154 162 def overdue?
155 163 effective_date && (effective_date < User.current.today) && (open_issues_count > 0)
156 164 end
157 165
158 166 # Returns assigned issues count
159 167 def issues_count
160 168 load_issue_counts
161 169 @issue_count
162 170 end
163 171
164 172 # Returns the total amount of open issues for this version.
165 173 def open_issues_count
166 174 load_issue_counts
167 175 @open_issues_count
168 176 end
169 177
170 178 # Returns the total amount of closed issues for this version.
171 179 def closed_issues_count
172 180 load_issue_counts
173 181 @closed_issues_count
174 182 end
175 183
176 184 def wiki_page
177 185 if project.wiki && !wiki_page_title.blank?
178 186 @wiki_page ||= project.wiki.find_page(wiki_page_title)
179 187 end
180 188 @wiki_page
181 189 end
182 190
183 191 def to_s; name end
184 192
185 193 def to_s_with_project
186 194 "#{project} - #{name}"
187 195 end
188 196
189 197 # Versions are sorted by effective_date and name
190 198 # Those with no effective_date are at the end, sorted by name
191 199 def <=>(version)
192 200 if self.effective_date
193 201 if version.effective_date
194 202 if self.effective_date == version.effective_date
195 203 name == version.name ? id <=> version.id : name <=> version.name
196 204 else
197 205 self.effective_date <=> version.effective_date
198 206 end
199 207 else
200 208 -1
201 209 end
202 210 else
203 211 if version.effective_date
204 212 1
205 213 else
206 214 name == version.name ? id <=> version.id : name <=> version.name
207 215 end
208 216 end
209 217 end
210 218
211 219 # Sort versions by status (open, locked then closed versions)
212 220 def self.sort_by_status(versions)
213 221 versions.sort do |a, b|
214 222 if a.status == b.status
215 223 a <=> b
216 224 else
217 225 b.status <=> a.status
218 226 end
219 227 end
220 228 end
221 229
222 230 def css_classes
223 231 [
224 232 completed? ? 'version-completed' : 'version-incompleted',
225 233 "version-#{status}"
226 234 ].join(' ')
227 235 end
228 236
229 237 def self.fields_for_order_statement(table=nil)
230 238 table ||= table_name
231 239 ["(CASE WHEN #{table}.effective_date IS NULL THEN 1 ELSE 0 END)", "#{table}.effective_date", "#{table}.name", "#{table}.id"]
232 240 end
233 241
234 242 scope :sorted, lambda { order(fields_for_order_statement) }
235 243
236 244 # Returns the sharings that +user+ can set the version to
237 245 def allowed_sharings(user = User.current)
238 246 VERSION_SHARINGS.select do |s|
239 247 if sharing == s
240 248 true
241 249 else
242 250 case s
243 251 when 'system'
244 252 # Only admin users can set a systemwide sharing
245 253 user.admin?
246 254 when 'hierarchy', 'tree'
247 255 # Only users allowed to manage versions of the root project can
248 256 # set sharing to hierarchy or tree
249 257 project.nil? || user.allowed_to?(:manage_versions, project.root)
250 258 else
251 259 true
252 260 end
253 261 end
254 262 end
255 263 end
256 264
257 265 # Returns true if the version is shared, otherwise false
258 266 def shared?
259 267 sharing != 'none'
260 268 end
261 269
262 270 def deletable?
263 271 fixed_issues.empty? && !referenced_by_a_custom_field?
264 272 end
265 273
274 def default_project_version
275 if @default_project_version.nil?
276 project.present? && project.default_version == self
277 else
278 @default_project_version
279 end
280 end
281
282 def default_project_version=(arg)
283 @default_project_version = (arg == '1' || arg == true)
284 end
285
266 286 private
267 287
268 288 def load_issue_counts
269 289 unless @issue_count
270 290 @open_issues_count = 0
271 291 @closed_issues_count = 0
272 292 fixed_issues.group(:status).count.each do |status, count|
273 293 if status.is_closed?
274 294 @closed_issues_count += count
275 295 else
276 296 @open_issues_count += count
277 297 end
278 298 end
279 299 @issue_count = @open_issues_count + @closed_issues_count
280 300 end
281 301 end
282 302
283 303 # Update the issue's fixed versions. Used if a version's sharing changes.
284 304 def update_issues_from_sharing_change
285 305 if sharing_changed?
286 306 if VERSION_SHARINGS.index(sharing_was).nil? ||
287 307 VERSION_SHARINGS.index(sharing).nil? ||
288 308 VERSION_SHARINGS.index(sharing_was) > VERSION_SHARINGS.index(sharing)
289 309 Issue.update_versions_from_sharing_change self
290 310 end
291 311 end
292 312 end
293 313
314 def update_default_project_version
315 if @default_project_version && project.present?
316 project.update_columns :default_version_id => id
317 end
318 end
319
294 320 # Returns the average estimated time of assigned issues
295 321 # or 1 if no issue has an estimated time
296 322 # Used to weight unestimated issues in progress calculation
297 323 def estimated_average
298 324 if @estimated_average.nil?
299 325 average = fixed_issues.average(:estimated_hours).to_f
300 326 if average == 0
301 327 average = 1
302 328 end
303 329 @estimated_average = average
304 330 end
305 331 @estimated_average
306 332 end
307 333
308 334 # Returns the total progress of open or closed issues. The returned percentage takes into account
309 335 # the amount of estimated time set for this version.
310 336 #
311 337 # Examples:
312 338 # issues_progress(true) => returns the progress percentage for open issues.
313 339 # issues_progress(false) => returns the progress percentage for closed issues.
314 340 def issues_progress(open)
315 341 @issues_progress ||= {}
316 342 @issues_progress[open] ||= begin
317 343 progress = 0
318 344 if issues_count > 0
319 345 ratio = open ? 'done_ratio' : 100
320 346
321 347 done = fixed_issues.open(open).sum("COALESCE(estimated_hours, #{estimated_average}) * #{ratio}").to_f
322 348 progress = done / (estimated_average * issues_count)
323 349 end
324 350 progress
325 351 end
326 352 end
327 353
328 354 def referenced_by_a_custom_field?
329 355 CustomValue.joins(:custom_field).
330 356 where(:value => id.to_s, :custom_fields => {:field_format => 'version'}).any?
331 357 end
332 358
333 359 def nullify_projects_default_version
334 360 Project.where(:default_version_id => id).update_all(:default_version_id => nil)
335 361 end
336 362 end
@@ -1,18 +1,21
1 1 <%= back_url_hidden_field_tag %>
2 2 <%= error_messages_for 'version' %>
3 3
4 4 <div class="box tabular">
5 5 <p><%= f.text_field :name, :size => 60, :required => true %></p>
6 6 <p><%= f.text_field :description, :size => 60 %></p>
7 7 <% unless @version.new_record? %>
8 8 <p><%= f.select :status, Version::VERSION_STATUSES.collect {|s| [l("version_status_#{s}"), s]} %></p>
9 9 <% end %>
10 10 <p><%= f.text_field :wiki_page_title, :label => :label_wiki_page, :size => 60, :disabled => @project.wiki.nil? %></p>
11 11 <p><%= f.date_field :effective_date, :size => 10 %><%= calendar_for('version_effective_date') %></p>
12 12 <p><%= f.select :sharing, @version.allowed_sharings.collect {|v| [format_version_sharing(v), v]} %></p>
13 <% if @version.new_record? %>
14 <p><%= f.check_box :default_project_version, :label => :field_default_version %></p>
15 <% end %>
13 16
14 17 <% @version.custom_field_values.each do |value| %>
15 18 <p><%= custom_field_tag_with_label :version, value %></p>
16 19 <% end %>
17 20
18 21 </div>
@@ -1,277 +1,293
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2016 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 VersionTest < ActiveSupport::TestCase
21 21 fixtures :projects, :users, :issues, :issue_statuses, :trackers,
22 22 :enumerations, :versions, :projects_trackers
23 23
24 24 def test_create
25 25 v = Version.new(:project => Project.find(1), :name => '1.1',
26 26 :effective_date => '2011-03-25')
27 27 assert v.save
28 28 assert_equal 'open', v.status
29 29 assert_equal 'none', v.sharing
30 30 end
31 31
32 def test_create_as_default_project_version
33 project = Project.find(1)
34 v = Version.new(:project => project, :name => '1.1',
35 :default_project_version => '1')
36 assert v.save
37 assert_equal v, project.reload.default_version
38 end
39
40 def test_create_not_as_default_project_version
41 project = Project.find(1)
42 v = Version.new(:project => project, :name => '1.1',
43 :default_project_version => '0')
44 assert v.save
45 assert_nil project.reload.default_version
46 end
47
32 48 def test_invalid_effective_date_validation
33 49 v = Version.new(:project => Project.find(1), :name => '1.1',
34 50 :effective_date => '99999-01-01')
35 51 assert !v.valid?
36 52 v.effective_date = '2012-11-33'
37 53 assert !v.valid?
38 54 v.effective_date = '2012-31-11'
39 55 assert !v.valid?
40 56 v.effective_date = '-2012-31-11'
41 57 assert !v.valid?
42 58 v.effective_date = 'ABC'
43 59 assert !v.valid?
44 60 assert_include I18n.translate('activerecord.errors.messages.not_a_date'),
45 61 v.errors[:effective_date]
46 62 end
47 63
48 64 def test_progress_should_be_0_with_no_assigned_issues
49 65 project = Project.find(1)
50 66 v = Version.create!(:project => project, :name => 'Progress')
51 67 assert_equal 0, v.completed_percent
52 68 assert_equal 0, v.closed_percent
53 69 end
54 70
55 71 def test_progress_should_be_0_with_unbegun_assigned_issues
56 72 project = Project.find(1)
57 73 v = Version.create!(:project => project, :name => 'Progress')
58 74 add_issue(v)
59 75 add_issue(v, :done_ratio => 0)
60 76 assert_progress_equal 0, v.completed_percent
61 77 assert_progress_equal 0, v.closed_percent
62 78 end
63 79
64 80 def test_progress_should_be_100_with_closed_assigned_issues
65 81 project = Project.find(1)
66 82 status = IssueStatus.where(:is_closed => true).first
67 83 v = Version.create!(:project => project, :name => 'Progress')
68 84 add_issue(v, :status => status)
69 85 add_issue(v, :status => status, :done_ratio => 20)
70 86 add_issue(v, :status => status, :done_ratio => 70, :estimated_hours => 25)
71 87 add_issue(v, :status => status, :estimated_hours => 15)
72 88 assert_progress_equal 100.0, v.completed_percent
73 89 assert_progress_equal 100.0, v.closed_percent
74 90 end
75 91
76 92 def test_progress_should_consider_done_ratio_of_open_assigned_issues
77 93 project = Project.find(1)
78 94 v = Version.create!(:project => project, :name => 'Progress')
79 95 add_issue(v)
80 96 add_issue(v, :done_ratio => 20)
81 97 add_issue(v, :done_ratio => 70)
82 98 assert_progress_equal (0.0 + 20.0 + 70.0)/3, v.completed_percent
83 99 assert_progress_equal 0, v.closed_percent
84 100 end
85 101
86 102 def test_progress_should_consider_closed_issues_as_completed
87 103 project = Project.find(1)
88 104 v = Version.create!(:project => project, :name => 'Progress')
89 105 add_issue(v)
90 106 add_issue(v, :done_ratio => 20)
91 107 add_issue(v, :status => IssueStatus.where(:is_closed => true).first)
92 108 assert_progress_equal (0.0 + 20.0 + 100.0)/3, v.completed_percent
93 109 assert_progress_equal (100.0)/3, v.closed_percent
94 110 end
95 111
96 112 def test_progress_should_consider_estimated_hours_to_weight_issues
97 113 project = Project.find(1)
98 114 v = Version.create!(:project => project, :name => 'Progress')
99 115 add_issue(v, :estimated_hours => 10)
100 116 add_issue(v, :estimated_hours => 20, :done_ratio => 30)
101 117 add_issue(v, :estimated_hours => 40, :done_ratio => 10)
102 118 add_issue(v, :estimated_hours => 25, :status => IssueStatus.where(:is_closed => true).first)
103 119 assert_progress_equal (10.0*0 + 20.0*0.3 + 40*0.1 + 25.0*1)/95.0*100, v.completed_percent
104 120 assert_progress_equal 25.0/95.0*100, v.closed_percent
105 121 end
106 122
107 123 def test_progress_should_consider_average_estimated_hours_to_weight_unestimated_issues
108 124 project = Project.find(1)
109 125 v = Version.create!(:project => project, :name => 'Progress')
110 126 add_issue(v, :done_ratio => 20)
111 127 add_issue(v, :status => IssueStatus.where(:is_closed => true).first)
112 128 add_issue(v, :estimated_hours => 10, :done_ratio => 30)
113 129 add_issue(v, :estimated_hours => 40, :done_ratio => 10)
114 130 assert_progress_equal (25.0*0.2 + 25.0*1 + 10.0*0.3 + 40.0*0.1)/100.0*100, v.completed_percent
115 131 assert_progress_equal 25.0/100.0*100, v.closed_percent
116 132 end
117 133
118 134 def test_should_sort_scheduled_then_unscheduled_versions
119 135 Version.delete_all
120 136 v4 = Version.create!(:project_id => 1, :name => 'v4')
121 137 v3 = Version.create!(:project_id => 1, :name => 'v2', :effective_date => '2012-07-14')
122 138 v2 = Version.create!(:project_id => 1, :name => 'v1')
123 139 v1 = Version.create!(:project_id => 1, :name => 'v3', :effective_date => '2012-08-02')
124 140 v5 = Version.create!(:project_id => 1, :name => 'v5', :effective_date => '2012-07-02')
125 141
126 142 assert_equal [v5, v3, v1, v2, v4], [v1, v2, v3, v4, v5].sort
127 143 assert_equal [v5, v3, v1, v2, v4], Version.sorted.to_a
128 144 end
129 145
130 146 def test_should_sort_versions_with_same_date_by_name
131 147 v1 = Version.new(:effective_date => '2014-12-03', :name => 'v2')
132 148 v2 = Version.new(:effective_date => '2014-12-03', :name => 'v1')
133 149 assert_equal [v2, v1], [v1, v2].sort
134 150 end
135 151
136 152 def test_completed_should_be_false_when_due_today
137 153 version = Version.create!(:project_id => 1, :effective_date => Date.today, :name => 'Due today')
138 154 assert_equal false, version.completed?
139 155 end
140 156
141 157 def test_completed_should_be_true_when_closed
142 158 version = Version.create!(:project_id => 1, :status => 'closed', :name => 'Closed')
143 159 assert_equal true, version.completed?
144 160 end
145 161
146 162 test "#behind_schedule? should be false if there are no issues assigned" do
147 163 version = Version.generate!(:effective_date => Date.yesterday)
148 164 assert_equal false, version.behind_schedule?
149 165 end
150 166
151 167 test "#behind_schedule? should be false if there is no effective_date" do
152 168 version = Version.generate!(:effective_date => nil)
153 169 assert_equal false, version.behind_schedule?
154 170 end
155 171
156 172 test "#behind_schedule? should be false if all of the issues are ahead of schedule" do
157 173 version = Version.create!(:project_id => 1, :name => 'test', :effective_date => 7.days.from_now.to_date)
158 174 add_issue(version, :start_date => 7.days.ago, :done_ratio => 60) # 14 day span, 60% done, 50% time left
159 175 add_issue(version, :start_date => 7.days.ago, :done_ratio => 60) # 14 day span, 60% done, 50% time left
160 176 assert_equal 60, version.completed_percent
161 177 assert_equal false, version.behind_schedule?
162 178 end
163 179
164 180 test "#behind_schedule? should be true if any of the issues are behind schedule" do
165 181 version = Version.create!(:project_id => 1, :name => 'test', :effective_date => 7.days.from_now.to_date)
166 182 add_issue(version, :start_date => 7.days.ago, :done_ratio => 60) # 14 day span, 60% done, 50% time left
167 183 add_issue(version, :start_date => 7.days.ago, :done_ratio => 20) # 14 day span, 20% done, 50% time left
168 184 assert_equal 40, version.completed_percent
169 185 assert_equal true, version.behind_schedule?
170 186 end
171 187
172 188 test "#behind_schedule? should be false if all of the issues are complete" do
173 189 version = Version.create!(:project_id => 1, :name => 'test', :effective_date => 7.days.from_now.to_date)
174 190 add_issue(version, :start_date => 14.days.ago, :done_ratio => 100, :status => IssueStatus.find(5)) # 7 day span
175 191 add_issue(version, :start_date => 14.days.ago, :done_ratio => 100, :status => IssueStatus.find(5)) # 7 day span
176 192 assert_equal 100, version.completed_percent
177 193 assert_equal false, version.behind_schedule?
178 194 end
179 195
180 196 test "#estimated_hours should return 0 with no assigned issues" do
181 197 version = Version.generate!
182 198 assert_equal 0, version.estimated_hours
183 199 end
184 200
185 201 test "#estimated_hours should return 0 with no estimated hours" do
186 202 version = Version.create!(:project_id => 1, :name => 'test')
187 203 add_issue(version)
188 204 assert_equal 0, version.estimated_hours
189 205 end
190 206
191 207 test "#estimated_hours should return return the sum of estimated hours" do
192 208 version = Version.create!(:project_id => 1, :name => 'test')
193 209 add_issue(version, :estimated_hours => 2.5)
194 210 add_issue(version, :estimated_hours => 5)
195 211 assert_equal 7.5, version.estimated_hours
196 212 end
197 213
198 214 test "#estimated_hours should return the sum of leaves estimated hours" do
199 215 version = Version.create!(:project_id => 1, :name => 'test')
200 216 parent = add_issue(version)
201 217 add_issue(version, :estimated_hours => 2.5, :parent_issue_id => parent.id)
202 218 add_issue(version, :estimated_hours => 5, :parent_issue_id => parent.id)
203 219 assert_equal 7.5, version.estimated_hours
204 220 end
205 221
206 222 test "should update all issue's fixed_version associations in case the hierarchy changed XXX" do
207 223 User.current = User.find(1) # Need the admin's permissions
208 224
209 225 @version = Version.find(7)
210 226 # Separate hierarchy
211 227 project_1_issue = Issue.find(1)
212 228 project_1_issue.fixed_version = @version
213 229 assert project_1_issue.save, project_1_issue.errors.full_messages.to_s
214 230
215 231 project_5_issue = Issue.find(6)
216 232 project_5_issue.fixed_version = @version
217 233 assert project_5_issue.save
218 234
219 235 # Project
220 236 project_2_issue = Issue.find(4)
221 237 project_2_issue.fixed_version = @version
222 238 assert project_2_issue.save
223 239
224 240 # Update the sharing
225 241 @version.sharing = 'none'
226 242 assert @version.save
227 243
228 244 # Project 1 now out of the shared scope
229 245 project_1_issue.reload
230 246 assert_equal nil, project_1_issue.fixed_version,
231 247 "Fixed version is still set after changing the Version's sharing"
232 248
233 249 # Project 5 now out of the shared scope
234 250 project_5_issue.reload
235 251 assert_equal nil, project_5_issue.fixed_version,
236 252 "Fixed version is still set after changing the Version's sharing"
237 253
238 254 # Project 2 issue remains
239 255 project_2_issue.reload
240 256 assert_equal @version, project_2_issue.fixed_version
241 257 end
242 258
243 259 def test_deletable_should_return_true_when_not_referenced
244 260 version = Version.generate!
245 261
246 262 assert_equal true, version.deletable?
247 263 end
248 264
249 265 def test_deletable_should_return_false_when_referenced_by_an_issue
250 266 version = Version.generate!
251 267 Issue.generate!(:fixed_version => version)
252 268
253 269 assert_equal false, version.deletable?
254 270 end
255 271
256 272 def test_deletable_should_return_false_when_referenced_by_a_custom_field
257 273 version = Version.generate!
258 274 field = IssueCustomField.generate!(:field_format => 'version')
259 275 value = CustomValue.create!(:custom_field => field, :customized => Issue.first, :value => version.id)
260 276
261 277 assert_equal false, version.deletable?
262 278 end
263 279
264 280 private
265 281
266 282 def add_issue(version, attributes={})
267 283 Issue.create!({:project => version.project,
268 284 :fixed_version => version,
269 285 :subject => 'Test',
270 286 :author => User.first,
271 287 :tracker => version.project.trackers.first}.merge(attributes))
272 288 end
273 289
274 290 def assert_progress_equal(expected_float, actual_float, message="")
275 291 assert_in_delta(expected_float, actual_float, 0.000001, message="")
276 292 end
277 293 end
General Comments 0
You need to be logged in to leave comments. Login now