##// END OF EJS Templates
Fixed that custom_field_values are not reloaded on #reload (#13119)....
Jean-Philippe Lang -
r11119:514f2d6c0fa6
parent child
Show More
@@ -1,160 +1,168
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2013 Jean-Philippe Lang
2 # Copyright (C) 2006-2013 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 module Redmine
18 module Redmine
19 module Acts
19 module Acts
20 module Customizable
20 module Customizable
21 def self.included(base)
21 def self.included(base)
22 base.extend ClassMethods
22 base.extend ClassMethods
23 end
23 end
24
24
25 module ClassMethods
25 module ClassMethods
26 def acts_as_customizable(options = {})
26 def acts_as_customizable(options = {})
27 return if self.included_modules.include?(Redmine::Acts::Customizable::InstanceMethods)
27 return if self.included_modules.include?(Redmine::Acts::Customizable::InstanceMethods)
28 cattr_accessor :customizable_options
28 cattr_accessor :customizable_options
29 self.customizable_options = options
29 self.customizable_options = options
30 has_many :custom_values, :as => :customized,
30 has_many :custom_values, :as => :customized,
31 :include => :custom_field,
31 :include => :custom_field,
32 :order => "#{CustomField.table_name}.position",
32 :order => "#{CustomField.table_name}.position",
33 :dependent => :delete_all,
33 :dependent => :delete_all,
34 :validate => false
34 :validate => false
35
36 send :alias_method, :reload_without_custom_fields, :reload
35 send :include, Redmine::Acts::Customizable::InstanceMethods
37 send :include, Redmine::Acts::Customizable::InstanceMethods
36 validate :validate_custom_field_values
38 validate :validate_custom_field_values
37 after_save :save_custom_field_values
39 after_save :save_custom_field_values
38 end
40 end
39 end
41 end
40
42
41 module InstanceMethods
43 module InstanceMethods
42 def self.included(base)
44 def self.included(base)
43 base.extend ClassMethods
45 base.extend ClassMethods
44 end
46 end
45
47
46 def available_custom_fields
48 def available_custom_fields
47 CustomField.where("type = '#{self.class.name}CustomField'").sorted.all
49 CustomField.where("type = '#{self.class.name}CustomField'").sorted.all
48 end
50 end
49
51
50 # Sets the values of the object's custom fields
52 # Sets the values of the object's custom fields
51 # values is an array like [{'id' => 1, 'value' => 'foo'}, {'id' => 2, 'value' => 'bar'}]
53 # values is an array like [{'id' => 1, 'value' => 'foo'}, {'id' => 2, 'value' => 'bar'}]
52 def custom_fields=(values)
54 def custom_fields=(values)
53 values_to_hash = values.inject({}) do |hash, v|
55 values_to_hash = values.inject({}) do |hash, v|
54 v = v.stringify_keys
56 v = v.stringify_keys
55 if v['id'] && v.has_key?('value')
57 if v['id'] && v.has_key?('value')
56 hash[v['id']] = v['value']
58 hash[v['id']] = v['value']
57 end
59 end
58 hash
60 hash
59 end
61 end
60 self.custom_field_values = values_to_hash
62 self.custom_field_values = values_to_hash
61 end
63 end
62
64
63 # Sets the values of the object's custom fields
65 # Sets the values of the object's custom fields
64 # values is a hash like {'1' => 'foo', 2 => 'bar'}
66 # values is a hash like {'1' => 'foo', 2 => 'bar'}
65 def custom_field_values=(values)
67 def custom_field_values=(values)
66 values = values.stringify_keys
68 values = values.stringify_keys
67
69
68 custom_field_values.each do |custom_field_value|
70 custom_field_values.each do |custom_field_value|
69 key = custom_field_value.custom_field_id.to_s
71 key = custom_field_value.custom_field_id.to_s
70 if values.has_key?(key)
72 if values.has_key?(key)
71 value = values[key]
73 value = values[key]
72 if value.is_a?(Array)
74 if value.is_a?(Array)
73 value = value.reject(&:blank?).uniq
75 value = value.reject(&:blank?).uniq
74 if value.empty?
76 if value.empty?
75 value << ''
77 value << ''
76 end
78 end
77 end
79 end
78 custom_field_value.value = value
80 custom_field_value.value = value
79 end
81 end
80 end
82 end
81 @custom_field_values_changed = true
83 @custom_field_values_changed = true
82 end
84 end
83
85
84 def custom_field_values
86 def custom_field_values
85 @custom_field_values ||= available_custom_fields.collect do |field|
87 @custom_field_values ||= available_custom_fields.collect do |field|
86 x = CustomFieldValue.new
88 x = CustomFieldValue.new
87 x.custom_field = field
89 x.custom_field = field
88 x.customized = self
90 x.customized = self
89 if field.multiple?
91 if field.multiple?
90 values = custom_values.select { |v| v.custom_field == field }
92 values = custom_values.select { |v| v.custom_field == field }
91 if values.empty?
93 if values.empty?
92 values << custom_values.build(:customized => self, :custom_field => field, :value => nil)
94 values << custom_values.build(:customized => self, :custom_field => field, :value => nil)
93 end
95 end
94 x.value = values.map(&:value)
96 x.value = values.map(&:value)
95 else
97 else
96 cv = custom_values.detect { |v| v.custom_field == field }
98 cv = custom_values.detect { |v| v.custom_field == field }
97 cv ||= custom_values.build(:customized => self, :custom_field => field, :value => nil)
99 cv ||= custom_values.build(:customized => self, :custom_field => field, :value => nil)
98 x.value = cv.value
100 x.value = cv.value
99 end
101 end
100 x
102 x
101 end
103 end
102 end
104 end
103
105
104 def visible_custom_field_values
106 def visible_custom_field_values
105 custom_field_values.select(&:visible?)
107 custom_field_values.select(&:visible?)
106 end
108 end
107
109
108 def custom_field_values_changed?
110 def custom_field_values_changed?
109 @custom_field_values_changed == true
111 @custom_field_values_changed == true
110 end
112 end
111
113
112 def custom_value_for(c)
114 def custom_value_for(c)
113 field_id = (c.is_a?(CustomField) ? c.id : c.to_i)
115 field_id = (c.is_a?(CustomField) ? c.id : c.to_i)
114 custom_values.detect {|v| v.custom_field_id == field_id }
116 custom_values.detect {|v| v.custom_field_id == field_id }
115 end
117 end
116
118
117 def custom_field_value(c)
119 def custom_field_value(c)
118 field_id = (c.is_a?(CustomField) ? c.id : c.to_i)
120 field_id = (c.is_a?(CustomField) ? c.id : c.to_i)
119 custom_field_values.detect {|v| v.custom_field_id == field_id }.try(:value)
121 custom_field_values.detect {|v| v.custom_field_id == field_id }.try(:value)
120 end
122 end
121
123
122 def validate_custom_field_values
124 def validate_custom_field_values
123 if new_record? || custom_field_values_changed?
125 if new_record? || custom_field_values_changed?
124 custom_field_values.each(&:validate_value)
126 custom_field_values.each(&:validate_value)
125 end
127 end
126 end
128 end
127
129
128 def save_custom_field_values
130 def save_custom_field_values
129 target_custom_values = []
131 target_custom_values = []
130 custom_field_values.each do |custom_field_value|
132 custom_field_values.each do |custom_field_value|
131 if custom_field_value.value.is_a?(Array)
133 if custom_field_value.value.is_a?(Array)
132 custom_field_value.value.each do |v|
134 custom_field_value.value.each do |v|
133 target = custom_values.detect {|cv| cv.custom_field == custom_field_value.custom_field && cv.value == v}
135 target = custom_values.detect {|cv| cv.custom_field == custom_field_value.custom_field && cv.value == v}
134 target ||= custom_values.build(:customized => self, :custom_field => custom_field_value.custom_field, :value => v)
136 target ||= custom_values.build(:customized => self, :custom_field => custom_field_value.custom_field, :value => v)
135 target_custom_values << target
137 target_custom_values << target
136 end
138 end
137 else
139 else
138 target = custom_values.detect {|cv| cv.custom_field == custom_field_value.custom_field}
140 target = custom_values.detect {|cv| cv.custom_field == custom_field_value.custom_field}
139 target ||= custom_values.build(:customized => self, :custom_field => custom_field_value.custom_field)
141 target ||= custom_values.build(:customized => self, :custom_field => custom_field_value.custom_field)
140 target.value = custom_field_value.value
142 target.value = custom_field_value.value
141 target_custom_values << target
143 target_custom_values << target
142 end
144 end
143 end
145 end
144 self.custom_values = target_custom_values
146 self.custom_values = target_custom_values
145 custom_values.each(&:save)
147 custom_values.each(&:save)
146 @custom_field_values_changed = false
148 @custom_field_values_changed = false
147 true
149 true
148 end
150 end
149
151
150 def reset_custom_values!
152 def reset_custom_values!
151 @custom_field_values = nil
153 @custom_field_values = nil
152 @custom_field_values_changed = true
154 @custom_field_values_changed = true
153 end
155 end
154
156
157 def reload(*args)
158 @custom_field_values = nil
159 @custom_field_values_changed = false
160 reload_without_custom_fields(*args)
161 end
162
155 module ClassMethods
163 module ClassMethods
156 end
164 end
157 end
165 end
158 end
166 end
159 end
167 end
160 end
168 end
@@ -1,1905 +1,1920
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2013 Jean-Philippe Lang
2 # Copyright (C) 2006-2013 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require File.expand_path('../../test_helper', __FILE__)
18 require File.expand_path('../../test_helper', __FILE__)
19
19
20 class IssueTest < ActiveSupport::TestCase
20 class IssueTest < ActiveSupport::TestCase
21 fixtures :projects, :users, :members, :member_roles, :roles,
21 fixtures :projects, :users, :members, :member_roles, :roles,
22 :groups_users,
22 :groups_users,
23 :trackers, :projects_trackers,
23 :trackers, :projects_trackers,
24 :enabled_modules,
24 :enabled_modules,
25 :versions,
25 :versions,
26 :issue_statuses, :issue_categories, :issue_relations, :workflows,
26 :issue_statuses, :issue_categories, :issue_relations, :workflows,
27 :enumerations,
27 :enumerations,
28 :issues, :journals, :journal_details,
28 :issues, :journals, :journal_details,
29 :custom_fields, :custom_fields_projects, :custom_fields_trackers, :custom_values,
29 :custom_fields, :custom_fields_projects, :custom_fields_trackers, :custom_values,
30 :time_entries
30 :time_entries
31
31
32 include Redmine::I18n
32 include Redmine::I18n
33
33
34 def teardown
34 def teardown
35 User.current = nil
35 User.current = nil
36 end
36 end
37
37
38 def test_create
38 def test_create
39 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3,
39 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3,
40 :status_id => 1, :priority => IssuePriority.all.first,
40 :status_id => 1, :priority => IssuePriority.all.first,
41 :subject => 'test_create',
41 :subject => 'test_create',
42 :description => 'IssueTest#test_create', :estimated_hours => '1:30')
42 :description => 'IssueTest#test_create', :estimated_hours => '1:30')
43 assert issue.save
43 assert issue.save
44 issue.reload
44 issue.reload
45 assert_equal 1.5, issue.estimated_hours
45 assert_equal 1.5, issue.estimated_hours
46 end
46 end
47
47
48 def test_create_minimal
48 def test_create_minimal
49 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3,
49 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3,
50 :status_id => 1, :priority => IssuePriority.all.first,
50 :status_id => 1, :priority => IssuePriority.all.first,
51 :subject => 'test_create')
51 :subject => 'test_create')
52 assert issue.save
52 assert issue.save
53 assert issue.description.nil?
53 assert issue.description.nil?
54 assert_nil issue.estimated_hours
54 assert_nil issue.estimated_hours
55 end
55 end
56
56
57 def test_start_date_format_should_be_validated
57 def test_start_date_format_should_be_validated
58 set_language_if_valid 'en'
58 set_language_if_valid 'en'
59 ['2012', 'ABC', '2012-15-20'].each do |invalid_date|
59 ['2012', 'ABC', '2012-15-20'].each do |invalid_date|
60 issue = Issue.new(:start_date => invalid_date)
60 issue = Issue.new(:start_date => invalid_date)
61 assert !issue.valid?
61 assert !issue.valid?
62 assert_include 'Start date is not a valid date', issue.errors.full_messages, "No error found for invalid date #{invalid_date}"
62 assert_include 'Start date is not a valid date', issue.errors.full_messages, "No error found for invalid date #{invalid_date}"
63 end
63 end
64 end
64 end
65
65
66 def test_due_date_format_should_be_validated
66 def test_due_date_format_should_be_validated
67 set_language_if_valid 'en'
67 set_language_if_valid 'en'
68 ['2012', 'ABC', '2012-15-20'].each do |invalid_date|
68 ['2012', 'ABC', '2012-15-20'].each do |invalid_date|
69 issue = Issue.new(:due_date => invalid_date)
69 issue = Issue.new(:due_date => invalid_date)
70 assert !issue.valid?
70 assert !issue.valid?
71 assert_include 'Due date is not a valid date', issue.errors.full_messages, "No error found for invalid date #{invalid_date}"
71 assert_include 'Due date is not a valid date', issue.errors.full_messages, "No error found for invalid date #{invalid_date}"
72 end
72 end
73 end
73 end
74
74
75 def test_due_date_lesser_than_start_date_should_not_validate
75 def test_due_date_lesser_than_start_date_should_not_validate
76 set_language_if_valid 'en'
76 set_language_if_valid 'en'
77 issue = Issue.new(:start_date => '2012-10-06', :due_date => '2012-10-02')
77 issue = Issue.new(:start_date => '2012-10-06', :due_date => '2012-10-02')
78 assert !issue.valid?
78 assert !issue.valid?
79 assert_include 'Due date must be greater than start date', issue.errors.full_messages
79 assert_include 'Due date must be greater than start date', issue.errors.full_messages
80 end
80 end
81
81
82 def test_estimated_hours_should_be_validated
82 def test_estimated_hours_should_be_validated
83 set_language_if_valid 'en'
83 set_language_if_valid 'en'
84 ['-2'].each do |invalid|
84 ['-2'].each do |invalid|
85 issue = Issue.new(:estimated_hours => invalid)
85 issue = Issue.new(:estimated_hours => invalid)
86 assert !issue.valid?
86 assert !issue.valid?
87 assert_include 'Estimated time is invalid', issue.errors.full_messages
87 assert_include 'Estimated time is invalid', issue.errors.full_messages
88 end
88 end
89 end
89 end
90
90
91 def test_create_with_required_custom_field
91 def test_create_with_required_custom_field
92 set_language_if_valid 'en'
92 set_language_if_valid 'en'
93 field = IssueCustomField.find_by_name('Database')
93 field = IssueCustomField.find_by_name('Database')
94 field.update_attribute(:is_required, true)
94 field.update_attribute(:is_required, true)
95
95
96 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1,
96 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1,
97 :status_id => 1, :subject => 'test_create',
97 :status_id => 1, :subject => 'test_create',
98 :description => 'IssueTest#test_create_with_required_custom_field')
98 :description => 'IssueTest#test_create_with_required_custom_field')
99 assert issue.available_custom_fields.include?(field)
99 assert issue.available_custom_fields.include?(field)
100 # No value for the custom field
100 # No value for the custom field
101 assert !issue.save
101 assert !issue.save
102 assert_equal ["Database can't be blank"], issue.errors.full_messages
102 assert_equal ["Database can't be blank"], issue.errors.full_messages
103 # Blank value
103 # Blank value
104 issue.custom_field_values = { field.id => '' }
104 issue.custom_field_values = { field.id => '' }
105 assert !issue.save
105 assert !issue.save
106 assert_equal ["Database can't be blank"], issue.errors.full_messages
106 assert_equal ["Database can't be blank"], issue.errors.full_messages
107 # Invalid value
107 # Invalid value
108 issue.custom_field_values = { field.id => 'SQLServer' }
108 issue.custom_field_values = { field.id => 'SQLServer' }
109 assert !issue.save
109 assert !issue.save
110 assert_equal ["Database is not included in the list"], issue.errors.full_messages
110 assert_equal ["Database is not included in the list"], issue.errors.full_messages
111 # Valid value
111 # Valid value
112 issue.custom_field_values = { field.id => 'PostgreSQL' }
112 issue.custom_field_values = { field.id => 'PostgreSQL' }
113 assert issue.save
113 assert issue.save
114 issue.reload
114 issue.reload
115 assert_equal 'PostgreSQL', issue.custom_value_for(field).value
115 assert_equal 'PostgreSQL', issue.custom_value_for(field).value
116 end
116 end
117
117
118 def test_create_with_group_assignment
118 def test_create_with_group_assignment
119 with_settings :issue_group_assignment => '1' do
119 with_settings :issue_group_assignment => '1' do
120 assert Issue.new(:project_id => 2, :tracker_id => 1, :author_id => 1,
120 assert Issue.new(:project_id => 2, :tracker_id => 1, :author_id => 1,
121 :subject => 'Group assignment',
121 :subject => 'Group assignment',
122 :assigned_to_id => 11).save
122 :assigned_to_id => 11).save
123 issue = Issue.first(:order => 'id DESC')
123 issue = Issue.first(:order => 'id DESC')
124 assert_kind_of Group, issue.assigned_to
124 assert_kind_of Group, issue.assigned_to
125 assert_equal Group.find(11), issue.assigned_to
125 assert_equal Group.find(11), issue.assigned_to
126 end
126 end
127 end
127 end
128
128
129 def test_create_with_parent_issue_id
129 def test_create_with_parent_issue_id
130 issue = Issue.new(:project_id => 1, :tracker_id => 1,
130 issue = Issue.new(:project_id => 1, :tracker_id => 1,
131 :author_id => 1, :subject => 'Group assignment',
131 :author_id => 1, :subject => 'Group assignment',
132 :parent_issue_id => 1)
132 :parent_issue_id => 1)
133 assert_save issue
133 assert_save issue
134 assert_equal 1, issue.parent_issue_id
134 assert_equal 1, issue.parent_issue_id
135 assert_equal Issue.find(1), issue.parent
135 assert_equal Issue.find(1), issue.parent
136 end
136 end
137
137
138 def test_create_with_sharp_parent_issue_id
138 def test_create_with_sharp_parent_issue_id
139 issue = Issue.new(:project_id => 1, :tracker_id => 1,
139 issue = Issue.new(:project_id => 1, :tracker_id => 1,
140 :author_id => 1, :subject => 'Group assignment',
140 :author_id => 1, :subject => 'Group assignment',
141 :parent_issue_id => "#1")
141 :parent_issue_id => "#1")
142 assert_save issue
142 assert_save issue
143 assert_equal 1, issue.parent_issue_id
143 assert_equal 1, issue.parent_issue_id
144 assert_equal Issue.find(1), issue.parent
144 assert_equal Issue.find(1), issue.parent
145 end
145 end
146
146
147 def test_create_with_invalid_parent_issue_id
147 def test_create_with_invalid_parent_issue_id
148 set_language_if_valid 'en'
148 set_language_if_valid 'en'
149 issue = Issue.new(:project_id => 1, :tracker_id => 1,
149 issue = Issue.new(:project_id => 1, :tracker_id => 1,
150 :author_id => 1, :subject => 'Group assignment',
150 :author_id => 1, :subject => 'Group assignment',
151 :parent_issue_id => '01ABC')
151 :parent_issue_id => '01ABC')
152 assert !issue.save
152 assert !issue.save
153 assert_equal '01ABC', issue.parent_issue_id
153 assert_equal '01ABC', issue.parent_issue_id
154 assert_include 'Parent task is invalid', issue.errors.full_messages
154 assert_include 'Parent task is invalid', issue.errors.full_messages
155 end
155 end
156
156
157 def test_create_with_invalid_sharp_parent_issue_id
157 def test_create_with_invalid_sharp_parent_issue_id
158 set_language_if_valid 'en'
158 set_language_if_valid 'en'
159 issue = Issue.new(:project_id => 1, :tracker_id => 1,
159 issue = Issue.new(:project_id => 1, :tracker_id => 1,
160 :author_id => 1, :subject => 'Group assignment',
160 :author_id => 1, :subject => 'Group assignment',
161 :parent_issue_id => '#01ABC')
161 :parent_issue_id => '#01ABC')
162 assert !issue.save
162 assert !issue.save
163 assert_equal '#01ABC', issue.parent_issue_id
163 assert_equal '#01ABC', issue.parent_issue_id
164 assert_include 'Parent task is invalid', issue.errors.full_messages
164 assert_include 'Parent task is invalid', issue.errors.full_messages
165 end
165 end
166
166
167 def assert_visibility_match(user, issues)
167 def assert_visibility_match(user, issues)
168 assert_equal issues.collect(&:id).sort, Issue.all.select {|issue| issue.visible?(user)}.collect(&:id).sort
168 assert_equal issues.collect(&:id).sort, Issue.all.select {|issue| issue.visible?(user)}.collect(&:id).sort
169 end
169 end
170
170
171 def test_visible_scope_for_anonymous
171 def test_visible_scope_for_anonymous
172 # Anonymous user should see issues of public projects only
172 # Anonymous user should see issues of public projects only
173 issues = Issue.visible(User.anonymous).all
173 issues = Issue.visible(User.anonymous).all
174 assert issues.any?
174 assert issues.any?
175 assert_nil issues.detect {|issue| !issue.project.is_public?}
175 assert_nil issues.detect {|issue| !issue.project.is_public?}
176 assert_nil issues.detect {|issue| issue.is_private?}
176 assert_nil issues.detect {|issue| issue.is_private?}
177 assert_visibility_match User.anonymous, issues
177 assert_visibility_match User.anonymous, issues
178 end
178 end
179
179
180 def test_visible_scope_for_anonymous_without_view_issues_permissions
180 def test_visible_scope_for_anonymous_without_view_issues_permissions
181 # Anonymous user should not see issues without permission
181 # Anonymous user should not see issues without permission
182 Role.anonymous.remove_permission!(:view_issues)
182 Role.anonymous.remove_permission!(:view_issues)
183 issues = Issue.visible(User.anonymous).all
183 issues = Issue.visible(User.anonymous).all
184 assert issues.empty?
184 assert issues.empty?
185 assert_visibility_match User.anonymous, issues
185 assert_visibility_match User.anonymous, issues
186 end
186 end
187
187
188 def test_anonymous_should_not_see_private_issues_with_issues_visibility_set_to_default
188 def test_anonymous_should_not_see_private_issues_with_issues_visibility_set_to_default
189 assert Role.anonymous.update_attribute(:issues_visibility, 'default')
189 assert Role.anonymous.update_attribute(:issues_visibility, 'default')
190 issue = Issue.generate!(:author => User.anonymous, :assigned_to => User.anonymous, :is_private => true)
190 issue = Issue.generate!(:author => User.anonymous, :assigned_to => User.anonymous, :is_private => true)
191 assert_nil Issue.where(:id => issue.id).visible(User.anonymous).first
191 assert_nil Issue.where(:id => issue.id).visible(User.anonymous).first
192 assert !issue.visible?(User.anonymous)
192 assert !issue.visible?(User.anonymous)
193 end
193 end
194
194
195 def test_anonymous_should_not_see_private_issues_with_issues_visibility_set_to_own
195 def test_anonymous_should_not_see_private_issues_with_issues_visibility_set_to_own
196 assert Role.anonymous.update_attribute(:issues_visibility, 'own')
196 assert Role.anonymous.update_attribute(:issues_visibility, 'own')
197 issue = Issue.generate!(:author => User.anonymous, :assigned_to => User.anonymous, :is_private => true)
197 issue = Issue.generate!(:author => User.anonymous, :assigned_to => User.anonymous, :is_private => true)
198 assert_nil Issue.where(:id => issue.id).visible(User.anonymous).first
198 assert_nil Issue.where(:id => issue.id).visible(User.anonymous).first
199 assert !issue.visible?(User.anonymous)
199 assert !issue.visible?(User.anonymous)
200 end
200 end
201
201
202 def test_visible_scope_for_non_member
202 def test_visible_scope_for_non_member
203 user = User.find(9)
203 user = User.find(9)
204 assert user.projects.empty?
204 assert user.projects.empty?
205 # Non member user should see issues of public projects only
205 # Non member user should see issues of public projects only
206 issues = Issue.visible(user).all
206 issues = Issue.visible(user).all
207 assert issues.any?
207 assert issues.any?
208 assert_nil issues.detect {|issue| !issue.project.is_public?}
208 assert_nil issues.detect {|issue| !issue.project.is_public?}
209 assert_nil issues.detect {|issue| issue.is_private?}
209 assert_nil issues.detect {|issue| issue.is_private?}
210 assert_visibility_match user, issues
210 assert_visibility_match user, issues
211 end
211 end
212
212
213 def test_visible_scope_for_non_member_with_own_issues_visibility
213 def test_visible_scope_for_non_member_with_own_issues_visibility
214 Role.non_member.update_attribute :issues_visibility, 'own'
214 Role.non_member.update_attribute :issues_visibility, 'own'
215 Issue.create!(:project_id => 1, :tracker_id => 1, :author_id => 9, :subject => 'Issue by non member')
215 Issue.create!(:project_id => 1, :tracker_id => 1, :author_id => 9, :subject => 'Issue by non member')
216 user = User.find(9)
216 user = User.find(9)
217
217
218 issues = Issue.visible(user).all
218 issues = Issue.visible(user).all
219 assert issues.any?
219 assert issues.any?
220 assert_nil issues.detect {|issue| issue.author != user}
220 assert_nil issues.detect {|issue| issue.author != user}
221 assert_visibility_match user, issues
221 assert_visibility_match user, issues
222 end
222 end
223
223
224 def test_visible_scope_for_non_member_without_view_issues_permissions
224 def test_visible_scope_for_non_member_without_view_issues_permissions
225 # Non member user should not see issues without permission
225 # Non member user should not see issues without permission
226 Role.non_member.remove_permission!(:view_issues)
226 Role.non_member.remove_permission!(:view_issues)
227 user = User.find(9)
227 user = User.find(9)
228 assert user.projects.empty?
228 assert user.projects.empty?
229 issues = Issue.visible(user).all
229 issues = Issue.visible(user).all
230 assert issues.empty?
230 assert issues.empty?
231 assert_visibility_match user, issues
231 assert_visibility_match user, issues
232 end
232 end
233
233
234 def test_visible_scope_for_member
234 def test_visible_scope_for_member
235 user = User.find(9)
235 user = User.find(9)
236 # User should see issues of projects for which he has view_issues permissions only
236 # User should see issues of projects for which he has view_issues permissions only
237 Role.non_member.remove_permission!(:view_issues)
237 Role.non_member.remove_permission!(:view_issues)
238 Member.create!(:principal => user, :project_id => 3, :role_ids => [2])
238 Member.create!(:principal => user, :project_id => 3, :role_ids => [2])
239 issues = Issue.visible(user).all
239 issues = Issue.visible(user).all
240 assert issues.any?
240 assert issues.any?
241 assert_nil issues.detect {|issue| issue.project_id != 3}
241 assert_nil issues.detect {|issue| issue.project_id != 3}
242 assert_nil issues.detect {|issue| issue.is_private?}
242 assert_nil issues.detect {|issue| issue.is_private?}
243 assert_visibility_match user, issues
243 assert_visibility_match user, issues
244 end
244 end
245
245
246 def test_visible_scope_for_member_with_groups_should_return_assigned_issues
246 def test_visible_scope_for_member_with_groups_should_return_assigned_issues
247 user = User.find(8)
247 user = User.find(8)
248 assert user.groups.any?
248 assert user.groups.any?
249 Member.create!(:principal => user.groups.first, :project_id => 1, :role_ids => [2])
249 Member.create!(:principal => user.groups.first, :project_id => 1, :role_ids => [2])
250 Role.non_member.remove_permission!(:view_issues)
250 Role.non_member.remove_permission!(:view_issues)
251
251
252 issue = Issue.create(:project_id => 1, :tracker_id => 1, :author_id => 3,
252 issue = Issue.create(:project_id => 1, :tracker_id => 1, :author_id => 3,
253 :status_id => 1, :priority => IssuePriority.all.first,
253 :status_id => 1, :priority => IssuePriority.all.first,
254 :subject => 'Assignment test',
254 :subject => 'Assignment test',
255 :assigned_to => user.groups.first,
255 :assigned_to => user.groups.first,
256 :is_private => true)
256 :is_private => true)
257
257
258 Role.find(2).update_attribute :issues_visibility, 'default'
258 Role.find(2).update_attribute :issues_visibility, 'default'
259 issues = Issue.visible(User.find(8)).all
259 issues = Issue.visible(User.find(8)).all
260 assert issues.any?
260 assert issues.any?
261 assert issues.include?(issue)
261 assert issues.include?(issue)
262
262
263 Role.find(2).update_attribute :issues_visibility, 'own'
263 Role.find(2).update_attribute :issues_visibility, 'own'
264 issues = Issue.visible(User.find(8)).all
264 issues = Issue.visible(User.find(8)).all
265 assert issues.any?
265 assert issues.any?
266 assert issues.include?(issue)
266 assert issues.include?(issue)
267 end
267 end
268
268
269 def test_visible_scope_for_admin
269 def test_visible_scope_for_admin
270 user = User.find(1)
270 user = User.find(1)
271 user.members.each(&:destroy)
271 user.members.each(&:destroy)
272 assert user.projects.empty?
272 assert user.projects.empty?
273 issues = Issue.visible(user).all
273 issues = Issue.visible(user).all
274 assert issues.any?
274 assert issues.any?
275 # Admin should see issues on private projects that he does not belong to
275 # Admin should see issues on private projects that he does not belong to
276 assert issues.detect {|issue| !issue.project.is_public?}
276 assert issues.detect {|issue| !issue.project.is_public?}
277 # Admin should see private issues of other users
277 # Admin should see private issues of other users
278 assert issues.detect {|issue| issue.is_private? && issue.author != user}
278 assert issues.detect {|issue| issue.is_private? && issue.author != user}
279 assert_visibility_match user, issues
279 assert_visibility_match user, issues
280 end
280 end
281
281
282 def test_visible_scope_with_project
282 def test_visible_scope_with_project
283 project = Project.find(1)
283 project = Project.find(1)
284 issues = Issue.visible(User.find(2), :project => project).all
284 issues = Issue.visible(User.find(2), :project => project).all
285 projects = issues.collect(&:project).uniq
285 projects = issues.collect(&:project).uniq
286 assert_equal 1, projects.size
286 assert_equal 1, projects.size
287 assert_equal project, projects.first
287 assert_equal project, projects.first
288 end
288 end
289
289
290 def test_visible_scope_with_project_and_subprojects
290 def test_visible_scope_with_project_and_subprojects
291 project = Project.find(1)
291 project = Project.find(1)
292 issues = Issue.visible(User.find(2), :project => project, :with_subprojects => true).all
292 issues = Issue.visible(User.find(2), :project => project, :with_subprojects => true).all
293 projects = issues.collect(&:project).uniq
293 projects = issues.collect(&:project).uniq
294 assert projects.size > 1
294 assert projects.size > 1
295 assert_equal [], projects.select {|p| !p.is_or_is_descendant_of?(project)}
295 assert_equal [], projects.select {|p| !p.is_or_is_descendant_of?(project)}
296 end
296 end
297
297
298 def test_visible_and_nested_set_scopes
298 def test_visible_and_nested_set_scopes
299 assert_equal 0, Issue.find(1).descendants.visible.all.size
299 assert_equal 0, Issue.find(1).descendants.visible.all.size
300 end
300 end
301
301
302 def test_open_scope
302 def test_open_scope
303 issues = Issue.open.all
303 issues = Issue.open.all
304 assert_nil issues.detect(&:closed?)
304 assert_nil issues.detect(&:closed?)
305 end
305 end
306
306
307 def test_open_scope_with_arg
307 def test_open_scope_with_arg
308 issues = Issue.open(false).all
308 issues = Issue.open(false).all
309 assert_equal issues, issues.select(&:closed?)
309 assert_equal issues, issues.select(&:closed?)
310 end
310 end
311
311
312 def test_fixed_version_scope_with_a_version_should_return_its_fixed_issues
312 def test_fixed_version_scope_with_a_version_should_return_its_fixed_issues
313 version = Version.find(2)
313 version = Version.find(2)
314 assert version.fixed_issues.any?
314 assert version.fixed_issues.any?
315 assert_equal version.fixed_issues.to_a.sort, Issue.fixed_version(version).to_a.sort
315 assert_equal version.fixed_issues.to_a.sort, Issue.fixed_version(version).to_a.sort
316 end
316 end
317
317
318 def test_fixed_version_scope_with_empty_array_should_return_no_result
318 def test_fixed_version_scope_with_empty_array_should_return_no_result
319 assert_equal 0, Issue.fixed_version([]).count
319 assert_equal 0, Issue.fixed_version([]).count
320 end
320 end
321
321
322 def test_errors_full_messages_should_include_custom_fields_errors
322 def test_errors_full_messages_should_include_custom_fields_errors
323 field = IssueCustomField.find_by_name('Database')
323 field = IssueCustomField.find_by_name('Database')
324
324
325 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1,
325 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1,
326 :status_id => 1, :subject => 'test_create',
326 :status_id => 1, :subject => 'test_create',
327 :description => 'IssueTest#test_create_with_required_custom_field')
327 :description => 'IssueTest#test_create_with_required_custom_field')
328 assert issue.available_custom_fields.include?(field)
328 assert issue.available_custom_fields.include?(field)
329 # Invalid value
329 # Invalid value
330 issue.custom_field_values = { field.id => 'SQLServer' }
330 issue.custom_field_values = { field.id => 'SQLServer' }
331
331
332 assert !issue.valid?
332 assert !issue.valid?
333 assert_equal 1, issue.errors.full_messages.size
333 assert_equal 1, issue.errors.full_messages.size
334 assert_equal "Database #{I18n.translate('activerecord.errors.messages.inclusion')}",
334 assert_equal "Database #{I18n.translate('activerecord.errors.messages.inclusion')}",
335 issue.errors.full_messages.first
335 issue.errors.full_messages.first
336 end
336 end
337
337
338 def test_update_issue_with_required_custom_field
338 def test_update_issue_with_required_custom_field
339 field = IssueCustomField.find_by_name('Database')
339 field = IssueCustomField.find_by_name('Database')
340 field.update_attribute(:is_required, true)
340 field.update_attribute(:is_required, true)
341
341
342 issue = Issue.find(1)
342 issue = Issue.find(1)
343 assert_nil issue.custom_value_for(field)
343 assert_nil issue.custom_value_for(field)
344 assert issue.available_custom_fields.include?(field)
344 assert issue.available_custom_fields.include?(field)
345 # No change to custom values, issue can be saved
345 # No change to custom values, issue can be saved
346 assert issue.save
346 assert issue.save
347 # Blank value
347 # Blank value
348 issue.custom_field_values = { field.id => '' }
348 issue.custom_field_values = { field.id => '' }
349 assert !issue.save
349 assert !issue.save
350 # Valid value
350 # Valid value
351 issue.custom_field_values = { field.id => 'PostgreSQL' }
351 issue.custom_field_values = { field.id => 'PostgreSQL' }
352 assert issue.save
352 assert issue.save
353 issue.reload
353 issue.reload
354 assert_equal 'PostgreSQL', issue.custom_value_for(field).value
354 assert_equal 'PostgreSQL', issue.custom_value_for(field).value
355 end
355 end
356
356
357 def test_should_not_update_attributes_if_custom_fields_validation_fails
357 def test_should_not_update_attributes_if_custom_fields_validation_fails
358 issue = Issue.find(1)
358 issue = Issue.find(1)
359 field = IssueCustomField.find_by_name('Database')
359 field = IssueCustomField.find_by_name('Database')
360 assert issue.available_custom_fields.include?(field)
360 assert issue.available_custom_fields.include?(field)
361
361
362 issue.custom_field_values = { field.id => 'Invalid' }
362 issue.custom_field_values = { field.id => 'Invalid' }
363 issue.subject = 'Should be not be saved'
363 issue.subject = 'Should be not be saved'
364 assert !issue.save
364 assert !issue.save
365
365
366 issue.reload
366 issue.reload
367 assert_equal "Can't print recipes", issue.subject
367 assert_equal "Can't print recipes", issue.subject
368 end
368 end
369
369
370 def test_should_not_recreate_custom_values_objects_on_update
370 def test_should_not_recreate_custom_values_objects_on_update
371 field = IssueCustomField.find_by_name('Database')
371 field = IssueCustomField.find_by_name('Database')
372
372
373 issue = Issue.find(1)
373 issue = Issue.find(1)
374 issue.custom_field_values = { field.id => 'PostgreSQL' }
374 issue.custom_field_values = { field.id => 'PostgreSQL' }
375 assert issue.save
375 assert issue.save
376 custom_value = issue.custom_value_for(field)
376 custom_value = issue.custom_value_for(field)
377 issue.reload
377 issue.reload
378 issue.custom_field_values = { field.id => 'MySQL' }
378 issue.custom_field_values = { field.id => 'MySQL' }
379 assert issue.save
379 assert issue.save
380 issue.reload
380 issue.reload
381 assert_equal custom_value.id, issue.custom_value_for(field).id
381 assert_equal custom_value.id, issue.custom_value_for(field).id
382 end
382 end
383
383
384 def test_should_not_update_custom_fields_on_changing_tracker_with_different_custom_fields
384 def test_should_not_update_custom_fields_on_changing_tracker_with_different_custom_fields
385 issue = Issue.create!(:project_id => 1, :tracker_id => 1, :author_id => 1,
385 issue = Issue.create!(:project_id => 1, :tracker_id => 1, :author_id => 1,
386 :status_id => 1, :subject => 'Test',
386 :status_id => 1, :subject => 'Test',
387 :custom_field_values => {'2' => 'Test'})
387 :custom_field_values => {'2' => 'Test'})
388 assert !Tracker.find(2).custom_field_ids.include?(2)
388 assert !Tracker.find(2).custom_field_ids.include?(2)
389
389
390 issue = Issue.find(issue.id)
390 issue = Issue.find(issue.id)
391 issue.attributes = {:tracker_id => 2, :custom_field_values => {'1' => ''}}
391 issue.attributes = {:tracker_id => 2, :custom_field_values => {'1' => ''}}
392
392
393 issue = Issue.find(issue.id)
393 issue = Issue.find(issue.id)
394 custom_value = issue.custom_value_for(2)
394 custom_value = issue.custom_value_for(2)
395 assert_not_nil custom_value
395 assert_not_nil custom_value
396 assert_equal 'Test', custom_value.value
396 assert_equal 'Test', custom_value.value
397 end
397 end
398
398
399 def test_assigning_tracker_id_should_reload_custom_fields_values
399 def test_assigning_tracker_id_should_reload_custom_fields_values
400 issue = Issue.new(:project => Project.find(1))
400 issue = Issue.new(:project => Project.find(1))
401 assert issue.custom_field_values.empty?
401 assert issue.custom_field_values.empty?
402 issue.tracker_id = 1
402 issue.tracker_id = 1
403 assert issue.custom_field_values.any?
403 assert issue.custom_field_values.any?
404 end
404 end
405
405
406 def test_assigning_attributes_should_assign_project_and_tracker_first
406 def test_assigning_attributes_should_assign_project_and_tracker_first
407 seq = sequence('seq')
407 seq = sequence('seq')
408 issue = Issue.new
408 issue = Issue.new
409 issue.expects(:project_id=).in_sequence(seq)
409 issue.expects(:project_id=).in_sequence(seq)
410 issue.expects(:tracker_id=).in_sequence(seq)
410 issue.expects(:tracker_id=).in_sequence(seq)
411 issue.expects(:subject=).in_sequence(seq)
411 issue.expects(:subject=).in_sequence(seq)
412 issue.attributes = {:tracker_id => 2, :project_id => 1, :subject => 'Test'}
412 issue.attributes = {:tracker_id => 2, :project_id => 1, :subject => 'Test'}
413 end
413 end
414
414
415 def test_assigning_tracker_and_custom_fields_should_assign_custom_fields
415 def test_assigning_tracker_and_custom_fields_should_assign_custom_fields
416 attributes = ActiveSupport::OrderedHash.new
416 attributes = ActiveSupport::OrderedHash.new
417 attributes['custom_field_values'] = { '1' => 'MySQL' }
417 attributes['custom_field_values'] = { '1' => 'MySQL' }
418 attributes['tracker_id'] = '1'
418 attributes['tracker_id'] = '1'
419 issue = Issue.new(:project => Project.find(1))
419 issue = Issue.new(:project => Project.find(1))
420 issue.attributes = attributes
420 issue.attributes = attributes
421 assert_equal 'MySQL', issue.custom_field_value(1)
421 assert_equal 'MySQL', issue.custom_field_value(1)
422 end
422 end
423
423
424 def test_reload_should_reload_custom_field_values
425 issue = Issue.generate!
426 issue.custom_field_values = {'2' => 'Foo'}
427 issue.save!
428
429 issue = Issue.order('id desc').first
430 assert_equal 'Foo', issue.custom_field_value(2)
431
432 issue.custom_field_values = {'2' => 'Bar'}
433 assert_equal 'Bar', issue.custom_field_value(2)
434
435 issue.reload
436 assert_equal 'Foo', issue.custom_field_value(2)
437 end
438
424 def test_should_update_issue_with_disabled_tracker
439 def test_should_update_issue_with_disabled_tracker
425 p = Project.find(1)
440 p = Project.find(1)
426 issue = Issue.find(1)
441 issue = Issue.find(1)
427
442
428 p.trackers.delete(issue.tracker)
443 p.trackers.delete(issue.tracker)
429 assert !p.trackers.include?(issue.tracker)
444 assert !p.trackers.include?(issue.tracker)
430
445
431 issue.reload
446 issue.reload
432 issue.subject = 'New subject'
447 issue.subject = 'New subject'
433 assert issue.save
448 assert issue.save
434 end
449 end
435
450
436 def test_should_not_set_a_disabled_tracker
451 def test_should_not_set_a_disabled_tracker
437 p = Project.find(1)
452 p = Project.find(1)
438 p.trackers.delete(Tracker.find(2))
453 p.trackers.delete(Tracker.find(2))
439
454
440 issue = Issue.find(1)
455 issue = Issue.find(1)
441 issue.tracker_id = 2
456 issue.tracker_id = 2
442 issue.subject = 'New subject'
457 issue.subject = 'New subject'
443 assert !issue.save
458 assert !issue.save
444 assert_not_nil issue.errors[:tracker_id]
459 assert_not_nil issue.errors[:tracker_id]
445 end
460 end
446
461
447 def test_category_based_assignment
462 def test_category_based_assignment
448 issue = Issue.create(:project_id => 1, :tracker_id => 1, :author_id => 3,
463 issue = Issue.create(:project_id => 1, :tracker_id => 1, :author_id => 3,
449 :status_id => 1, :priority => IssuePriority.all.first,
464 :status_id => 1, :priority => IssuePriority.all.first,
450 :subject => 'Assignment test',
465 :subject => 'Assignment test',
451 :description => 'Assignment test', :category_id => 1)
466 :description => 'Assignment test', :category_id => 1)
452 assert_equal IssueCategory.find(1).assigned_to, issue.assigned_to
467 assert_equal IssueCategory.find(1).assigned_to, issue.assigned_to
453 end
468 end
454
469
455 def test_new_statuses_allowed_to
470 def test_new_statuses_allowed_to
456 WorkflowTransition.delete_all
471 WorkflowTransition.delete_all
457 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1,
472 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1,
458 :old_status_id => 1, :new_status_id => 2,
473 :old_status_id => 1, :new_status_id => 2,
459 :author => false, :assignee => false)
474 :author => false, :assignee => false)
460 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1,
475 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1,
461 :old_status_id => 1, :new_status_id => 3,
476 :old_status_id => 1, :new_status_id => 3,
462 :author => true, :assignee => false)
477 :author => true, :assignee => false)
463 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 1,
478 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 1,
464 :new_status_id => 4, :author => false,
479 :new_status_id => 4, :author => false,
465 :assignee => true)
480 :assignee => true)
466 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1,
481 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1,
467 :old_status_id => 1, :new_status_id => 5,
482 :old_status_id => 1, :new_status_id => 5,
468 :author => true, :assignee => true)
483 :author => true, :assignee => true)
469 status = IssueStatus.find(1)
484 status = IssueStatus.find(1)
470 role = Role.find(1)
485 role = Role.find(1)
471 tracker = Tracker.find(1)
486 tracker = Tracker.find(1)
472 user = User.find(2)
487 user = User.find(2)
473
488
474 issue = Issue.generate!(:tracker => tracker, :status => status,
489 issue = Issue.generate!(:tracker => tracker, :status => status,
475 :project_id => 1, :author_id => 1)
490 :project_id => 1, :author_id => 1)
476 assert_equal [1, 2], issue.new_statuses_allowed_to(user).map(&:id)
491 assert_equal [1, 2], issue.new_statuses_allowed_to(user).map(&:id)
477
492
478 issue = Issue.generate!(:tracker => tracker, :status => status,
493 issue = Issue.generate!(:tracker => tracker, :status => status,
479 :project_id => 1, :author => user)
494 :project_id => 1, :author => user)
480 assert_equal [1, 2, 3, 5], issue.new_statuses_allowed_to(user).map(&:id)
495 assert_equal [1, 2, 3, 5], issue.new_statuses_allowed_to(user).map(&:id)
481
496
482 issue = Issue.generate!(:tracker => tracker, :status => status,
497 issue = Issue.generate!(:tracker => tracker, :status => status,
483 :project_id => 1, :author_id => 1,
498 :project_id => 1, :author_id => 1,
484 :assigned_to => user)
499 :assigned_to => user)
485 assert_equal [1, 2, 4, 5], issue.new_statuses_allowed_to(user).map(&:id)
500 assert_equal [1, 2, 4, 5], issue.new_statuses_allowed_to(user).map(&:id)
486
501
487 issue = Issue.generate!(:tracker => tracker, :status => status,
502 issue = Issue.generate!(:tracker => tracker, :status => status,
488 :project_id => 1, :author => user,
503 :project_id => 1, :author => user,
489 :assigned_to => user)
504 :assigned_to => user)
490 assert_equal [1, 2, 3, 4, 5], issue.new_statuses_allowed_to(user).map(&:id)
505 assert_equal [1, 2, 3, 4, 5], issue.new_statuses_allowed_to(user).map(&:id)
491 end
506 end
492
507
493 def test_new_statuses_allowed_to_should_return_all_transitions_for_admin
508 def test_new_statuses_allowed_to_should_return_all_transitions_for_admin
494 admin = User.find(1)
509 admin = User.find(1)
495 issue = Issue.find(1)
510 issue = Issue.find(1)
496 assert !admin.member_of?(issue.project)
511 assert !admin.member_of?(issue.project)
497 expected_statuses = [issue.status] +
512 expected_statuses = [issue.status] +
498 WorkflowTransition.find_all_by_old_status_id(
513 WorkflowTransition.find_all_by_old_status_id(
499 issue.status_id).map(&:new_status).uniq.sort
514 issue.status_id).map(&:new_status).uniq.sort
500 assert_equal expected_statuses, issue.new_statuses_allowed_to(admin)
515 assert_equal expected_statuses, issue.new_statuses_allowed_to(admin)
501 end
516 end
502
517
503 def test_new_statuses_allowed_to_should_return_default_and_current_status_when_copying
518 def test_new_statuses_allowed_to_should_return_default_and_current_status_when_copying
504 issue = Issue.find(1).copy
519 issue = Issue.find(1).copy
505 assert_equal [1], issue.new_statuses_allowed_to(User.find(2)).map(&:id)
520 assert_equal [1], issue.new_statuses_allowed_to(User.find(2)).map(&:id)
506
521
507 issue = Issue.find(2).copy
522 issue = Issue.find(2).copy
508 assert_equal [1, 2], issue.new_statuses_allowed_to(User.find(2)).map(&:id)
523 assert_equal [1, 2], issue.new_statuses_allowed_to(User.find(2)).map(&:id)
509 end
524 end
510
525
511 def test_safe_attributes_names_should_not_include_disabled_field
526 def test_safe_attributes_names_should_not_include_disabled_field
512 tracker = Tracker.new(:core_fields => %w(assigned_to_id fixed_version_id))
527 tracker = Tracker.new(:core_fields => %w(assigned_to_id fixed_version_id))
513
528
514 issue = Issue.new(:tracker => tracker)
529 issue = Issue.new(:tracker => tracker)
515 assert_include 'tracker_id', issue.safe_attribute_names
530 assert_include 'tracker_id', issue.safe_attribute_names
516 assert_include 'status_id', issue.safe_attribute_names
531 assert_include 'status_id', issue.safe_attribute_names
517 assert_include 'subject', issue.safe_attribute_names
532 assert_include 'subject', issue.safe_attribute_names
518 assert_include 'description', issue.safe_attribute_names
533 assert_include 'description', issue.safe_attribute_names
519 assert_include 'custom_field_values', issue.safe_attribute_names
534 assert_include 'custom_field_values', issue.safe_attribute_names
520 assert_include 'custom_fields', issue.safe_attribute_names
535 assert_include 'custom_fields', issue.safe_attribute_names
521 assert_include 'lock_version', issue.safe_attribute_names
536 assert_include 'lock_version', issue.safe_attribute_names
522
537
523 tracker.core_fields.each do |field|
538 tracker.core_fields.each do |field|
524 assert_include field, issue.safe_attribute_names
539 assert_include field, issue.safe_attribute_names
525 end
540 end
526
541
527 tracker.disabled_core_fields.each do |field|
542 tracker.disabled_core_fields.each do |field|
528 assert_not_include field, issue.safe_attribute_names
543 assert_not_include field, issue.safe_attribute_names
529 end
544 end
530 end
545 end
531
546
532 def test_safe_attributes_should_ignore_disabled_fields
547 def test_safe_attributes_should_ignore_disabled_fields
533 tracker = Tracker.find(1)
548 tracker = Tracker.find(1)
534 tracker.core_fields = %w(assigned_to_id due_date)
549 tracker.core_fields = %w(assigned_to_id due_date)
535 tracker.save!
550 tracker.save!
536
551
537 issue = Issue.new(:tracker => tracker)
552 issue = Issue.new(:tracker => tracker)
538 issue.safe_attributes = {'start_date' => '2012-07-14', 'due_date' => '2012-07-14'}
553 issue.safe_attributes = {'start_date' => '2012-07-14', 'due_date' => '2012-07-14'}
539 assert_nil issue.start_date
554 assert_nil issue.start_date
540 assert_equal Date.parse('2012-07-14'), issue.due_date
555 assert_equal Date.parse('2012-07-14'), issue.due_date
541 end
556 end
542
557
543 def test_safe_attributes_should_accept_target_tracker_enabled_fields
558 def test_safe_attributes_should_accept_target_tracker_enabled_fields
544 source = Tracker.find(1)
559 source = Tracker.find(1)
545 source.core_fields = []
560 source.core_fields = []
546 source.save!
561 source.save!
547 target = Tracker.find(2)
562 target = Tracker.find(2)
548 target.core_fields = %w(assigned_to_id due_date)
563 target.core_fields = %w(assigned_to_id due_date)
549 target.save!
564 target.save!
550
565
551 issue = Issue.new(:tracker => source)
566 issue = Issue.new(:tracker => source)
552 issue.safe_attributes = {'tracker_id' => 2, 'due_date' => '2012-07-14'}
567 issue.safe_attributes = {'tracker_id' => 2, 'due_date' => '2012-07-14'}
553 assert_equal target, issue.tracker
568 assert_equal target, issue.tracker
554 assert_equal Date.parse('2012-07-14'), issue.due_date
569 assert_equal Date.parse('2012-07-14'), issue.due_date
555 end
570 end
556
571
557 def test_safe_attributes_should_not_include_readonly_fields
572 def test_safe_attributes_should_not_include_readonly_fields
558 WorkflowPermission.delete_all
573 WorkflowPermission.delete_all
559 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
574 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
560 :role_id => 1, :field_name => 'due_date',
575 :role_id => 1, :field_name => 'due_date',
561 :rule => 'readonly')
576 :rule => 'readonly')
562 user = User.find(2)
577 user = User.find(2)
563
578
564 issue = Issue.new(:project_id => 1, :tracker_id => 1)
579 issue = Issue.new(:project_id => 1, :tracker_id => 1)
565 assert_equal %w(due_date), issue.read_only_attribute_names(user)
580 assert_equal %w(due_date), issue.read_only_attribute_names(user)
566 assert_not_include 'due_date', issue.safe_attribute_names(user)
581 assert_not_include 'due_date', issue.safe_attribute_names(user)
567
582
568 issue.send :safe_attributes=, {'start_date' => '2012-07-14', 'due_date' => '2012-07-14'}, user
583 issue.send :safe_attributes=, {'start_date' => '2012-07-14', 'due_date' => '2012-07-14'}, user
569 assert_equal Date.parse('2012-07-14'), issue.start_date
584 assert_equal Date.parse('2012-07-14'), issue.start_date
570 assert_nil issue.due_date
585 assert_nil issue.due_date
571 end
586 end
572
587
573 def test_safe_attributes_should_not_include_readonly_custom_fields
588 def test_safe_attributes_should_not_include_readonly_custom_fields
574 cf1 = IssueCustomField.create!(:name => 'Writable field',
589 cf1 = IssueCustomField.create!(:name => 'Writable field',
575 :field_format => 'string',
590 :field_format => 'string',
576 :is_for_all => true, :tracker_ids => [1])
591 :is_for_all => true, :tracker_ids => [1])
577 cf2 = IssueCustomField.create!(:name => 'Readonly field',
592 cf2 = IssueCustomField.create!(:name => 'Readonly field',
578 :field_format => 'string',
593 :field_format => 'string',
579 :is_for_all => true, :tracker_ids => [1])
594 :is_for_all => true, :tracker_ids => [1])
580 WorkflowPermission.delete_all
595 WorkflowPermission.delete_all
581 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
596 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
582 :role_id => 1, :field_name => cf2.id.to_s,
597 :role_id => 1, :field_name => cf2.id.to_s,
583 :rule => 'readonly')
598 :rule => 'readonly')
584 user = User.find(2)
599 user = User.find(2)
585 issue = Issue.new(:project_id => 1, :tracker_id => 1)
600 issue = Issue.new(:project_id => 1, :tracker_id => 1)
586 assert_equal [cf2.id.to_s], issue.read_only_attribute_names(user)
601 assert_equal [cf2.id.to_s], issue.read_only_attribute_names(user)
587 assert_not_include cf2.id.to_s, issue.safe_attribute_names(user)
602 assert_not_include cf2.id.to_s, issue.safe_attribute_names(user)
588
603
589 issue.send :safe_attributes=, {'custom_field_values' => {
604 issue.send :safe_attributes=, {'custom_field_values' => {
590 cf1.id.to_s => 'value1', cf2.id.to_s => 'value2'
605 cf1.id.to_s => 'value1', cf2.id.to_s => 'value2'
591 }}, user
606 }}, user
592 assert_equal 'value1', issue.custom_field_value(cf1)
607 assert_equal 'value1', issue.custom_field_value(cf1)
593 assert_nil issue.custom_field_value(cf2)
608 assert_nil issue.custom_field_value(cf2)
594
609
595 issue.send :safe_attributes=, {'custom_fields' => [
610 issue.send :safe_attributes=, {'custom_fields' => [
596 {'id' => cf1.id.to_s, 'value' => 'valuea'},
611 {'id' => cf1.id.to_s, 'value' => 'valuea'},
597 {'id' => cf2.id.to_s, 'value' => 'valueb'}
612 {'id' => cf2.id.to_s, 'value' => 'valueb'}
598 ]}, user
613 ]}, user
599 assert_equal 'valuea', issue.custom_field_value(cf1)
614 assert_equal 'valuea', issue.custom_field_value(cf1)
600 assert_nil issue.custom_field_value(cf2)
615 assert_nil issue.custom_field_value(cf2)
601 end
616 end
602
617
603 def test_editable_custom_field_values_should_return_non_readonly_custom_values
618 def test_editable_custom_field_values_should_return_non_readonly_custom_values
604 cf1 = IssueCustomField.create!(:name => 'Writable field', :field_format => 'string',
619 cf1 = IssueCustomField.create!(:name => 'Writable field', :field_format => 'string',
605 :is_for_all => true, :tracker_ids => [1, 2])
620 :is_for_all => true, :tracker_ids => [1, 2])
606 cf2 = IssueCustomField.create!(:name => 'Readonly field', :field_format => 'string',
621 cf2 = IssueCustomField.create!(:name => 'Readonly field', :field_format => 'string',
607 :is_for_all => true, :tracker_ids => [1, 2])
622 :is_for_all => true, :tracker_ids => [1, 2])
608 WorkflowPermission.delete_all
623 WorkflowPermission.delete_all
609 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1, :role_id => 1,
624 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1, :role_id => 1,
610 :field_name => cf2.id.to_s, :rule => 'readonly')
625 :field_name => cf2.id.to_s, :rule => 'readonly')
611 user = User.find(2)
626 user = User.find(2)
612
627
613 issue = Issue.new(:project_id => 1, :tracker_id => 1)
628 issue = Issue.new(:project_id => 1, :tracker_id => 1)
614 values = issue.editable_custom_field_values(user)
629 values = issue.editable_custom_field_values(user)
615 assert values.detect {|value| value.custom_field == cf1}
630 assert values.detect {|value| value.custom_field == cf1}
616 assert_nil values.detect {|value| value.custom_field == cf2}
631 assert_nil values.detect {|value| value.custom_field == cf2}
617
632
618 issue.tracker_id = 2
633 issue.tracker_id = 2
619 values = issue.editable_custom_field_values(user)
634 values = issue.editable_custom_field_values(user)
620 assert values.detect {|value| value.custom_field == cf1}
635 assert values.detect {|value| value.custom_field == cf1}
621 assert values.detect {|value| value.custom_field == cf2}
636 assert values.detect {|value| value.custom_field == cf2}
622 end
637 end
623
638
624 def test_safe_attributes_should_accept_target_tracker_writable_fields
639 def test_safe_attributes_should_accept_target_tracker_writable_fields
625 WorkflowPermission.delete_all
640 WorkflowPermission.delete_all
626 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
641 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
627 :role_id => 1, :field_name => 'due_date',
642 :role_id => 1, :field_name => 'due_date',
628 :rule => 'readonly')
643 :rule => 'readonly')
629 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 2,
644 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 2,
630 :role_id => 1, :field_name => 'start_date',
645 :role_id => 1, :field_name => 'start_date',
631 :rule => 'readonly')
646 :rule => 'readonly')
632 user = User.find(2)
647 user = User.find(2)
633
648
634 issue = Issue.new(:project_id => 1, :tracker_id => 1, :status_id => 1)
649 issue = Issue.new(:project_id => 1, :tracker_id => 1, :status_id => 1)
635
650
636 issue.send :safe_attributes=, {'start_date' => '2012-07-12',
651 issue.send :safe_attributes=, {'start_date' => '2012-07-12',
637 'due_date' => '2012-07-14'}, user
652 'due_date' => '2012-07-14'}, user
638 assert_equal Date.parse('2012-07-12'), issue.start_date
653 assert_equal Date.parse('2012-07-12'), issue.start_date
639 assert_nil issue.due_date
654 assert_nil issue.due_date
640
655
641 issue.send :safe_attributes=, {'start_date' => '2012-07-15',
656 issue.send :safe_attributes=, {'start_date' => '2012-07-15',
642 'due_date' => '2012-07-16',
657 'due_date' => '2012-07-16',
643 'tracker_id' => 2}, user
658 'tracker_id' => 2}, user
644 assert_equal Date.parse('2012-07-12'), issue.start_date
659 assert_equal Date.parse('2012-07-12'), issue.start_date
645 assert_equal Date.parse('2012-07-16'), issue.due_date
660 assert_equal Date.parse('2012-07-16'), issue.due_date
646 end
661 end
647
662
648 def test_safe_attributes_should_accept_target_status_writable_fields
663 def test_safe_attributes_should_accept_target_status_writable_fields
649 WorkflowPermission.delete_all
664 WorkflowPermission.delete_all
650 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
665 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
651 :role_id => 1, :field_name => 'due_date',
666 :role_id => 1, :field_name => 'due_date',
652 :rule => 'readonly')
667 :rule => 'readonly')
653 WorkflowPermission.create!(:old_status_id => 2, :tracker_id => 1,
668 WorkflowPermission.create!(:old_status_id => 2, :tracker_id => 1,
654 :role_id => 1, :field_name => 'start_date',
669 :role_id => 1, :field_name => 'start_date',
655 :rule => 'readonly')
670 :rule => 'readonly')
656 user = User.find(2)
671 user = User.find(2)
657
672
658 issue = Issue.new(:project_id => 1, :tracker_id => 1, :status_id => 1)
673 issue = Issue.new(:project_id => 1, :tracker_id => 1, :status_id => 1)
659
674
660 issue.send :safe_attributes=, {'start_date' => '2012-07-12',
675 issue.send :safe_attributes=, {'start_date' => '2012-07-12',
661 'due_date' => '2012-07-14'},
676 'due_date' => '2012-07-14'},
662 user
677 user
663 assert_equal Date.parse('2012-07-12'), issue.start_date
678 assert_equal Date.parse('2012-07-12'), issue.start_date
664 assert_nil issue.due_date
679 assert_nil issue.due_date
665
680
666 issue.send :safe_attributes=, {'start_date' => '2012-07-15',
681 issue.send :safe_attributes=, {'start_date' => '2012-07-15',
667 'due_date' => '2012-07-16',
682 'due_date' => '2012-07-16',
668 'status_id' => 2},
683 'status_id' => 2},
669 user
684 user
670 assert_equal Date.parse('2012-07-12'), issue.start_date
685 assert_equal Date.parse('2012-07-12'), issue.start_date
671 assert_equal Date.parse('2012-07-16'), issue.due_date
686 assert_equal Date.parse('2012-07-16'), issue.due_date
672 end
687 end
673
688
674 def test_required_attributes_should_be_validated
689 def test_required_attributes_should_be_validated
675 cf = IssueCustomField.create!(:name => 'Foo', :field_format => 'string',
690 cf = IssueCustomField.create!(:name => 'Foo', :field_format => 'string',
676 :is_for_all => true, :tracker_ids => [1, 2])
691 :is_for_all => true, :tracker_ids => [1, 2])
677
692
678 WorkflowPermission.delete_all
693 WorkflowPermission.delete_all
679 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
694 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
680 :role_id => 1, :field_name => 'due_date',
695 :role_id => 1, :field_name => 'due_date',
681 :rule => 'required')
696 :rule => 'required')
682 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
697 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
683 :role_id => 1, :field_name => 'category_id',
698 :role_id => 1, :field_name => 'category_id',
684 :rule => 'required')
699 :rule => 'required')
685 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
700 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
686 :role_id => 1, :field_name => cf.id.to_s,
701 :role_id => 1, :field_name => cf.id.to_s,
687 :rule => 'required')
702 :rule => 'required')
688
703
689 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 2,
704 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 2,
690 :role_id => 1, :field_name => 'start_date',
705 :role_id => 1, :field_name => 'start_date',
691 :rule => 'required')
706 :rule => 'required')
692 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 2,
707 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 2,
693 :role_id => 1, :field_name => cf.id.to_s,
708 :role_id => 1, :field_name => cf.id.to_s,
694 :rule => 'required')
709 :rule => 'required')
695 user = User.find(2)
710 user = User.find(2)
696
711
697 issue = Issue.new(:project_id => 1, :tracker_id => 1,
712 issue = Issue.new(:project_id => 1, :tracker_id => 1,
698 :status_id => 1, :subject => 'Required fields',
713 :status_id => 1, :subject => 'Required fields',
699 :author => user)
714 :author => user)
700 assert_equal [cf.id.to_s, "category_id", "due_date"],
715 assert_equal [cf.id.to_s, "category_id", "due_date"],
701 issue.required_attribute_names(user).sort
716 issue.required_attribute_names(user).sort
702 assert !issue.save, "Issue was saved"
717 assert !issue.save, "Issue was saved"
703 assert_equal ["Category can't be blank", "Due date can't be blank", "Foo can't be blank"],
718 assert_equal ["Category can't be blank", "Due date can't be blank", "Foo can't be blank"],
704 issue.errors.full_messages.sort
719 issue.errors.full_messages.sort
705
720
706 issue.tracker_id = 2
721 issue.tracker_id = 2
707 assert_equal [cf.id.to_s, "start_date"], issue.required_attribute_names(user).sort
722 assert_equal [cf.id.to_s, "start_date"], issue.required_attribute_names(user).sort
708 assert !issue.save, "Issue was saved"
723 assert !issue.save, "Issue was saved"
709 assert_equal ["Foo can't be blank", "Start date can't be blank"],
724 assert_equal ["Foo can't be blank", "Start date can't be blank"],
710 issue.errors.full_messages.sort
725 issue.errors.full_messages.sort
711
726
712 issue.start_date = Date.today
727 issue.start_date = Date.today
713 issue.custom_field_values = {cf.id.to_s => 'bar'}
728 issue.custom_field_values = {cf.id.to_s => 'bar'}
714 assert issue.save
729 assert issue.save
715 end
730 end
716
731
717 def test_required_attribute_names_for_multiple_roles_should_intersect_rules
732 def test_required_attribute_names_for_multiple_roles_should_intersect_rules
718 WorkflowPermission.delete_all
733 WorkflowPermission.delete_all
719 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
734 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
720 :role_id => 1, :field_name => 'due_date',
735 :role_id => 1, :field_name => 'due_date',
721 :rule => 'required')
736 :rule => 'required')
722 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
737 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
723 :role_id => 1, :field_name => 'start_date',
738 :role_id => 1, :field_name => 'start_date',
724 :rule => 'required')
739 :rule => 'required')
725 user = User.find(2)
740 user = User.find(2)
726 member = Member.find(1)
741 member = Member.find(1)
727 issue = Issue.new(:project_id => 1, :tracker_id => 1, :status_id => 1)
742 issue = Issue.new(:project_id => 1, :tracker_id => 1, :status_id => 1)
728
743
729 assert_equal %w(due_date start_date), issue.required_attribute_names(user).sort
744 assert_equal %w(due_date start_date), issue.required_attribute_names(user).sort
730
745
731 member.role_ids = [1, 2]
746 member.role_ids = [1, 2]
732 member.save!
747 member.save!
733 assert_equal [], issue.required_attribute_names(user.reload)
748 assert_equal [], issue.required_attribute_names(user.reload)
734
749
735 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
750 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
736 :role_id => 2, :field_name => 'due_date',
751 :role_id => 2, :field_name => 'due_date',
737 :rule => 'required')
752 :rule => 'required')
738 assert_equal %w(due_date), issue.required_attribute_names(user)
753 assert_equal %w(due_date), issue.required_attribute_names(user)
739
754
740 member.role_ids = [1, 2, 3]
755 member.role_ids = [1, 2, 3]
741 member.save!
756 member.save!
742 assert_equal [], issue.required_attribute_names(user.reload)
757 assert_equal [], issue.required_attribute_names(user.reload)
743
758
744 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
759 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
745 :role_id => 2, :field_name => 'due_date',
760 :role_id => 2, :field_name => 'due_date',
746 :rule => 'readonly')
761 :rule => 'readonly')
747 # required + readonly => required
762 # required + readonly => required
748 assert_equal %w(due_date), issue.required_attribute_names(user)
763 assert_equal %w(due_date), issue.required_attribute_names(user)
749 end
764 end
750
765
751 def test_read_only_attribute_names_for_multiple_roles_should_intersect_rules
766 def test_read_only_attribute_names_for_multiple_roles_should_intersect_rules
752 WorkflowPermission.delete_all
767 WorkflowPermission.delete_all
753 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
768 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
754 :role_id => 1, :field_name => 'due_date',
769 :role_id => 1, :field_name => 'due_date',
755 :rule => 'readonly')
770 :rule => 'readonly')
756 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
771 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
757 :role_id => 1, :field_name => 'start_date',
772 :role_id => 1, :field_name => 'start_date',
758 :rule => 'readonly')
773 :rule => 'readonly')
759 user = User.find(2)
774 user = User.find(2)
760 member = Member.find(1)
775 member = Member.find(1)
761 issue = Issue.new(:project_id => 1, :tracker_id => 1, :status_id => 1)
776 issue = Issue.new(:project_id => 1, :tracker_id => 1, :status_id => 1)
762
777
763 assert_equal %w(due_date start_date), issue.read_only_attribute_names(user).sort
778 assert_equal %w(due_date start_date), issue.read_only_attribute_names(user).sort
764
779
765 member.role_ids = [1, 2]
780 member.role_ids = [1, 2]
766 member.save!
781 member.save!
767 assert_equal [], issue.read_only_attribute_names(user.reload)
782 assert_equal [], issue.read_only_attribute_names(user.reload)
768
783
769 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
784 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1,
770 :role_id => 2, :field_name => 'due_date',
785 :role_id => 2, :field_name => 'due_date',
771 :rule => 'readonly')
786 :rule => 'readonly')
772 assert_equal %w(due_date), issue.read_only_attribute_names(user)
787 assert_equal %w(due_date), issue.read_only_attribute_names(user)
773 end
788 end
774
789
775 def test_copy
790 def test_copy
776 issue = Issue.new.copy_from(1)
791 issue = Issue.new.copy_from(1)
777 assert issue.copy?
792 assert issue.copy?
778 assert issue.save
793 assert issue.save
779 issue.reload
794 issue.reload
780 orig = Issue.find(1)
795 orig = Issue.find(1)
781 assert_equal orig.subject, issue.subject
796 assert_equal orig.subject, issue.subject
782 assert_equal orig.tracker, issue.tracker
797 assert_equal orig.tracker, issue.tracker
783 assert_equal "125", issue.custom_value_for(2).value
798 assert_equal "125", issue.custom_value_for(2).value
784 end
799 end
785
800
786 def test_copy_should_copy_status
801 def test_copy_should_copy_status
787 orig = Issue.find(8)
802 orig = Issue.find(8)
788 assert orig.status != IssueStatus.default
803 assert orig.status != IssueStatus.default
789
804
790 issue = Issue.new.copy_from(orig)
805 issue = Issue.new.copy_from(orig)
791 assert issue.save
806 assert issue.save
792 issue.reload
807 issue.reload
793 assert_equal orig.status, issue.status
808 assert_equal orig.status, issue.status
794 end
809 end
795
810
796 def test_copy_should_add_relation_with_copied_issue
811 def test_copy_should_add_relation_with_copied_issue
797 copied = Issue.find(1)
812 copied = Issue.find(1)
798 issue = Issue.new.copy_from(copied)
813 issue = Issue.new.copy_from(copied)
799 assert issue.save
814 assert issue.save
800 issue.reload
815 issue.reload
801
816
802 assert_equal 1, issue.relations.size
817 assert_equal 1, issue.relations.size
803 relation = issue.relations.first
818 relation = issue.relations.first
804 assert_equal 'copied_to', relation.relation_type
819 assert_equal 'copied_to', relation.relation_type
805 assert_equal copied, relation.issue_from
820 assert_equal copied, relation.issue_from
806 assert_equal issue, relation.issue_to
821 assert_equal issue, relation.issue_to
807 end
822 end
808
823
809 def test_copy_should_copy_subtasks
824 def test_copy_should_copy_subtasks
810 issue = Issue.generate_with_descendants!
825 issue = Issue.generate_with_descendants!
811
826
812 copy = issue.reload.copy
827 copy = issue.reload.copy
813 copy.author = User.find(7)
828 copy.author = User.find(7)
814 assert_difference 'Issue.count', 1+issue.descendants.count do
829 assert_difference 'Issue.count', 1+issue.descendants.count do
815 assert copy.save
830 assert copy.save
816 end
831 end
817 copy.reload
832 copy.reload
818 assert_equal %w(Child1 Child2), copy.children.map(&:subject).sort
833 assert_equal %w(Child1 Child2), copy.children.map(&:subject).sort
819 child_copy = copy.children.detect {|c| c.subject == 'Child1'}
834 child_copy = copy.children.detect {|c| c.subject == 'Child1'}
820 assert_equal %w(Child11), child_copy.children.map(&:subject).sort
835 assert_equal %w(Child11), child_copy.children.map(&:subject).sort
821 assert_equal copy.author, child_copy.author
836 assert_equal copy.author, child_copy.author
822 end
837 end
823
838
824 def test_copy_should_copy_subtasks_to_target_project
839 def test_copy_should_copy_subtasks_to_target_project
825 issue = Issue.generate_with_descendants!
840 issue = Issue.generate_with_descendants!
826
841
827 copy = issue.copy(:project_id => 3)
842 copy = issue.copy(:project_id => 3)
828 assert_difference 'Issue.count', 1+issue.descendants.count do
843 assert_difference 'Issue.count', 1+issue.descendants.count do
829 assert copy.save
844 assert copy.save
830 end
845 end
831 assert_equal [3], copy.reload.descendants.map(&:project_id).uniq
846 assert_equal [3], copy.reload.descendants.map(&:project_id).uniq
832 end
847 end
833
848
834 def test_copy_should_not_copy_subtasks_twice_when_saving_twice
849 def test_copy_should_not_copy_subtasks_twice_when_saving_twice
835 issue = Issue.generate_with_descendants!
850 issue = Issue.generate_with_descendants!
836
851
837 copy = issue.reload.copy
852 copy = issue.reload.copy
838 assert_difference 'Issue.count', 1+issue.descendants.count do
853 assert_difference 'Issue.count', 1+issue.descendants.count do
839 assert copy.save
854 assert copy.save
840 assert copy.save
855 assert copy.save
841 end
856 end
842 end
857 end
843
858
844 def test_should_not_call_after_project_change_on_creation
859 def test_should_not_call_after_project_change_on_creation
845 issue = Issue.new(:project_id => 1, :tracker_id => 1, :status_id => 1,
860 issue = Issue.new(:project_id => 1, :tracker_id => 1, :status_id => 1,
846 :subject => 'Test', :author_id => 1)
861 :subject => 'Test', :author_id => 1)
847 issue.expects(:after_project_change).never
862 issue.expects(:after_project_change).never
848 issue.save!
863 issue.save!
849 end
864 end
850
865
851 def test_should_not_call_after_project_change_on_update
866 def test_should_not_call_after_project_change_on_update
852 issue = Issue.find(1)
867 issue = Issue.find(1)
853 issue.project = Project.find(1)
868 issue.project = Project.find(1)
854 issue.subject = 'No project change'
869 issue.subject = 'No project change'
855 issue.expects(:after_project_change).never
870 issue.expects(:after_project_change).never
856 issue.save!
871 issue.save!
857 end
872 end
858
873
859 def test_should_call_after_project_change_on_project_change
874 def test_should_call_after_project_change_on_project_change
860 issue = Issue.find(1)
875 issue = Issue.find(1)
861 issue.project = Project.find(2)
876 issue.project = Project.find(2)
862 issue.expects(:after_project_change).once
877 issue.expects(:after_project_change).once
863 issue.save!
878 issue.save!
864 end
879 end
865
880
866 def test_adding_journal_should_update_timestamp
881 def test_adding_journal_should_update_timestamp
867 issue = Issue.find(1)
882 issue = Issue.find(1)
868 updated_on_was = issue.updated_on
883 updated_on_was = issue.updated_on
869
884
870 issue.init_journal(User.first, "Adding notes")
885 issue.init_journal(User.first, "Adding notes")
871 assert_difference 'Journal.count' do
886 assert_difference 'Journal.count' do
872 assert issue.save
887 assert issue.save
873 end
888 end
874 issue.reload
889 issue.reload
875
890
876 assert_not_equal updated_on_was, issue.updated_on
891 assert_not_equal updated_on_was, issue.updated_on
877 end
892 end
878
893
879 def test_should_close_duplicates
894 def test_should_close_duplicates
880 # Create 3 issues
895 # Create 3 issues
881 issue1 = Issue.generate!
896 issue1 = Issue.generate!
882 issue2 = Issue.generate!
897 issue2 = Issue.generate!
883 issue3 = Issue.generate!
898 issue3 = Issue.generate!
884
899
885 # 2 is a dupe of 1
900 # 2 is a dupe of 1
886 IssueRelation.create!(:issue_from => issue2, :issue_to => issue1,
901 IssueRelation.create!(:issue_from => issue2, :issue_to => issue1,
887 :relation_type => IssueRelation::TYPE_DUPLICATES)
902 :relation_type => IssueRelation::TYPE_DUPLICATES)
888 # And 3 is a dupe of 2
903 # And 3 is a dupe of 2
889 IssueRelation.create!(:issue_from => issue3, :issue_to => issue2,
904 IssueRelation.create!(:issue_from => issue3, :issue_to => issue2,
890 :relation_type => IssueRelation::TYPE_DUPLICATES)
905 :relation_type => IssueRelation::TYPE_DUPLICATES)
891 # And 3 is a dupe of 1 (circular duplicates)
906 # And 3 is a dupe of 1 (circular duplicates)
892 IssueRelation.create!(:issue_from => issue3, :issue_to => issue1,
907 IssueRelation.create!(:issue_from => issue3, :issue_to => issue1,
893 :relation_type => IssueRelation::TYPE_DUPLICATES)
908 :relation_type => IssueRelation::TYPE_DUPLICATES)
894
909
895 assert issue1.reload.duplicates.include?(issue2)
910 assert issue1.reload.duplicates.include?(issue2)
896
911
897 # Closing issue 1
912 # Closing issue 1
898 issue1.init_journal(User.first, "Closing issue1")
913 issue1.init_journal(User.first, "Closing issue1")
899 issue1.status = IssueStatus.where(:is_closed => true).first
914 issue1.status = IssueStatus.where(:is_closed => true).first
900 assert issue1.save
915 assert issue1.save
901 # 2 and 3 should be also closed
916 # 2 and 3 should be also closed
902 assert issue2.reload.closed?
917 assert issue2.reload.closed?
903 assert issue3.reload.closed?
918 assert issue3.reload.closed?
904 end
919 end
905
920
906 def test_should_not_close_duplicated_issue
921 def test_should_not_close_duplicated_issue
907 issue1 = Issue.generate!
922 issue1 = Issue.generate!
908 issue2 = Issue.generate!
923 issue2 = Issue.generate!
909
924
910 # 2 is a dupe of 1
925 # 2 is a dupe of 1
911 IssueRelation.create(:issue_from => issue2, :issue_to => issue1,
926 IssueRelation.create(:issue_from => issue2, :issue_to => issue1,
912 :relation_type => IssueRelation::TYPE_DUPLICATES)
927 :relation_type => IssueRelation::TYPE_DUPLICATES)
913 # 2 is a dup of 1 but 1 is not a duplicate of 2
928 # 2 is a dup of 1 but 1 is not a duplicate of 2
914 assert !issue2.reload.duplicates.include?(issue1)
929 assert !issue2.reload.duplicates.include?(issue1)
915
930
916 # Closing issue 2
931 # Closing issue 2
917 issue2.init_journal(User.first, "Closing issue2")
932 issue2.init_journal(User.first, "Closing issue2")
918 issue2.status = IssueStatus.where(:is_closed => true).first
933 issue2.status = IssueStatus.where(:is_closed => true).first
919 assert issue2.save
934 assert issue2.save
920 # 1 should not be also closed
935 # 1 should not be also closed
921 assert !issue1.reload.closed?
936 assert !issue1.reload.closed?
922 end
937 end
923
938
924 def test_assignable_versions
939 def test_assignable_versions
925 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1,
940 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1,
926 :status_id => 1, :fixed_version_id => 1,
941 :status_id => 1, :fixed_version_id => 1,
927 :subject => 'New issue')
942 :subject => 'New issue')
928 assert_equal ['open'], issue.assignable_versions.collect(&:status).uniq
943 assert_equal ['open'], issue.assignable_versions.collect(&:status).uniq
929 end
944 end
930
945
931 def test_should_not_be_able_to_assign_a_new_issue_to_a_closed_version
946 def test_should_not_be_able_to_assign_a_new_issue_to_a_closed_version
932 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1,
947 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1,
933 :status_id => 1, :fixed_version_id => 1,
948 :status_id => 1, :fixed_version_id => 1,
934 :subject => 'New issue')
949 :subject => 'New issue')
935 assert !issue.save
950 assert !issue.save
936 assert_not_nil issue.errors[:fixed_version_id]
951 assert_not_nil issue.errors[:fixed_version_id]
937 end
952 end
938
953
939 def test_should_not_be_able_to_assign_a_new_issue_to_a_locked_version
954 def test_should_not_be_able_to_assign_a_new_issue_to_a_locked_version
940 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1,
955 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1,
941 :status_id => 1, :fixed_version_id => 2,
956 :status_id => 1, :fixed_version_id => 2,
942 :subject => 'New issue')
957 :subject => 'New issue')
943 assert !issue.save
958 assert !issue.save
944 assert_not_nil issue.errors[:fixed_version_id]
959 assert_not_nil issue.errors[:fixed_version_id]
945 end
960 end
946
961
947 def test_should_be_able_to_assign_a_new_issue_to_an_open_version
962 def test_should_be_able_to_assign_a_new_issue_to_an_open_version
948 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1,
963 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1,
949 :status_id => 1, :fixed_version_id => 3,
964 :status_id => 1, :fixed_version_id => 3,
950 :subject => 'New issue')
965 :subject => 'New issue')
951 assert issue.save
966 assert issue.save
952 end
967 end
953
968
954 def test_should_be_able_to_update_an_issue_assigned_to_a_closed_version
969 def test_should_be_able_to_update_an_issue_assigned_to_a_closed_version
955 issue = Issue.find(11)
970 issue = Issue.find(11)
956 assert_equal 'closed', issue.fixed_version.status
971 assert_equal 'closed', issue.fixed_version.status
957 issue.subject = 'Subject changed'
972 issue.subject = 'Subject changed'
958 assert issue.save
973 assert issue.save
959 end
974 end
960
975
961 def test_should_not_be_able_to_reopen_an_issue_assigned_to_a_closed_version
976 def test_should_not_be_able_to_reopen_an_issue_assigned_to_a_closed_version
962 issue = Issue.find(11)
977 issue = Issue.find(11)
963 issue.status_id = 1
978 issue.status_id = 1
964 assert !issue.save
979 assert !issue.save
965 assert_not_nil issue.errors[:base]
980 assert_not_nil issue.errors[:base]
966 end
981 end
967
982
968 def test_should_be_able_to_reopen_and_reassign_an_issue_assigned_to_a_closed_version
983 def test_should_be_able_to_reopen_and_reassign_an_issue_assigned_to_a_closed_version
969 issue = Issue.find(11)
984 issue = Issue.find(11)
970 issue.status_id = 1
985 issue.status_id = 1
971 issue.fixed_version_id = 3
986 issue.fixed_version_id = 3
972 assert issue.save
987 assert issue.save
973 end
988 end
974
989
975 def test_should_be_able_to_reopen_an_issue_assigned_to_a_locked_version
990 def test_should_be_able_to_reopen_an_issue_assigned_to_a_locked_version
976 issue = Issue.find(12)
991 issue = Issue.find(12)
977 assert_equal 'locked', issue.fixed_version.status
992 assert_equal 'locked', issue.fixed_version.status
978 issue.status_id = 1
993 issue.status_id = 1
979 assert issue.save
994 assert issue.save
980 end
995 end
981
996
982 def test_should_not_be_able_to_keep_unshared_version_when_changing_project
997 def test_should_not_be_able_to_keep_unshared_version_when_changing_project
983 issue = Issue.find(2)
998 issue = Issue.find(2)
984 assert_equal 2, issue.fixed_version_id
999 assert_equal 2, issue.fixed_version_id
985 issue.project_id = 3
1000 issue.project_id = 3
986 assert_nil issue.fixed_version_id
1001 assert_nil issue.fixed_version_id
987 issue.fixed_version_id = 2
1002 issue.fixed_version_id = 2
988 assert !issue.save
1003 assert !issue.save
989 assert_include 'Target version is not included in the list', issue.errors.full_messages
1004 assert_include 'Target version is not included in the list', issue.errors.full_messages
990 end
1005 end
991
1006
992 def test_should_keep_shared_version_when_changing_project
1007 def test_should_keep_shared_version_when_changing_project
993 Version.find(2).update_attribute :sharing, 'tree'
1008 Version.find(2).update_attribute :sharing, 'tree'
994
1009
995 issue = Issue.find(2)
1010 issue = Issue.find(2)
996 assert_equal 2, issue.fixed_version_id
1011 assert_equal 2, issue.fixed_version_id
997 issue.project_id = 3
1012 issue.project_id = 3
998 assert_equal 2, issue.fixed_version_id
1013 assert_equal 2, issue.fixed_version_id
999 assert issue.save
1014 assert issue.save
1000 end
1015 end
1001
1016
1002 def test_allowed_target_projects_on_move_should_include_projects_with_issue_tracking_enabled
1017 def test_allowed_target_projects_on_move_should_include_projects_with_issue_tracking_enabled
1003 assert_include Project.find(2), Issue.allowed_target_projects_on_move(User.find(2))
1018 assert_include Project.find(2), Issue.allowed_target_projects_on_move(User.find(2))
1004 end
1019 end
1005
1020
1006 def test_allowed_target_projects_on_move_should_not_include_projects_with_issue_tracking_disabled
1021 def test_allowed_target_projects_on_move_should_not_include_projects_with_issue_tracking_disabled
1007 Project.find(2).disable_module! :issue_tracking
1022 Project.find(2).disable_module! :issue_tracking
1008 assert_not_include Project.find(2), Issue.allowed_target_projects_on_move(User.find(2))
1023 assert_not_include Project.find(2), Issue.allowed_target_projects_on_move(User.find(2))
1009 end
1024 end
1010
1025
1011 def test_move_to_another_project_with_same_category
1026 def test_move_to_another_project_with_same_category
1012 issue = Issue.find(1)
1027 issue = Issue.find(1)
1013 issue.project = Project.find(2)
1028 issue.project = Project.find(2)
1014 assert issue.save
1029 assert issue.save
1015 issue.reload
1030 issue.reload
1016 assert_equal 2, issue.project_id
1031 assert_equal 2, issue.project_id
1017 # Category changes
1032 # Category changes
1018 assert_equal 4, issue.category_id
1033 assert_equal 4, issue.category_id
1019 # Make sure time entries were move to the target project
1034 # Make sure time entries were move to the target project
1020 assert_equal 2, issue.time_entries.first.project_id
1035 assert_equal 2, issue.time_entries.first.project_id
1021 end
1036 end
1022
1037
1023 def test_move_to_another_project_without_same_category
1038 def test_move_to_another_project_without_same_category
1024 issue = Issue.find(2)
1039 issue = Issue.find(2)
1025 issue.project = Project.find(2)
1040 issue.project = Project.find(2)
1026 assert issue.save
1041 assert issue.save
1027 issue.reload
1042 issue.reload
1028 assert_equal 2, issue.project_id
1043 assert_equal 2, issue.project_id
1029 # Category cleared
1044 # Category cleared
1030 assert_nil issue.category_id
1045 assert_nil issue.category_id
1031 end
1046 end
1032
1047
1033 def test_move_to_another_project_should_clear_fixed_version_when_not_shared
1048 def test_move_to_another_project_should_clear_fixed_version_when_not_shared
1034 issue = Issue.find(1)
1049 issue = Issue.find(1)
1035 issue.update_attribute(:fixed_version_id, 1)
1050 issue.update_attribute(:fixed_version_id, 1)
1036 issue.project = Project.find(2)
1051 issue.project = Project.find(2)
1037 assert issue.save
1052 assert issue.save
1038 issue.reload
1053 issue.reload
1039 assert_equal 2, issue.project_id
1054 assert_equal 2, issue.project_id
1040 # Cleared fixed_version
1055 # Cleared fixed_version
1041 assert_equal nil, issue.fixed_version
1056 assert_equal nil, issue.fixed_version
1042 end
1057 end
1043
1058
1044 def test_move_to_another_project_should_keep_fixed_version_when_shared_with_the_target_project
1059 def test_move_to_another_project_should_keep_fixed_version_when_shared_with_the_target_project
1045 issue = Issue.find(1)
1060 issue = Issue.find(1)
1046 issue.update_attribute(:fixed_version_id, 4)
1061 issue.update_attribute(:fixed_version_id, 4)
1047 issue.project = Project.find(5)
1062 issue.project = Project.find(5)
1048 assert issue.save
1063 assert issue.save
1049 issue.reload
1064 issue.reload
1050 assert_equal 5, issue.project_id
1065 assert_equal 5, issue.project_id
1051 # Keep fixed_version
1066 # Keep fixed_version
1052 assert_equal 4, issue.fixed_version_id
1067 assert_equal 4, issue.fixed_version_id
1053 end
1068 end
1054
1069
1055 def test_move_to_another_project_should_clear_fixed_version_when_not_shared_with_the_target_project
1070 def test_move_to_another_project_should_clear_fixed_version_when_not_shared_with_the_target_project
1056 issue = Issue.find(1)
1071 issue = Issue.find(1)
1057 issue.update_attribute(:fixed_version_id, 1)
1072 issue.update_attribute(:fixed_version_id, 1)
1058 issue.project = Project.find(5)
1073 issue.project = Project.find(5)
1059 assert issue.save
1074 assert issue.save
1060 issue.reload
1075 issue.reload
1061 assert_equal 5, issue.project_id
1076 assert_equal 5, issue.project_id
1062 # Cleared fixed_version
1077 # Cleared fixed_version
1063 assert_equal nil, issue.fixed_version
1078 assert_equal nil, issue.fixed_version
1064 end
1079 end
1065
1080
1066 def test_move_to_another_project_should_keep_fixed_version_when_shared_systemwide
1081 def test_move_to_another_project_should_keep_fixed_version_when_shared_systemwide
1067 issue = Issue.find(1)
1082 issue = Issue.find(1)
1068 issue.update_attribute(:fixed_version_id, 7)
1083 issue.update_attribute(:fixed_version_id, 7)
1069 issue.project = Project.find(2)
1084 issue.project = Project.find(2)
1070 assert issue.save
1085 assert issue.save
1071 issue.reload
1086 issue.reload
1072 assert_equal 2, issue.project_id
1087 assert_equal 2, issue.project_id
1073 # Keep fixed_version
1088 # Keep fixed_version
1074 assert_equal 7, issue.fixed_version_id
1089 assert_equal 7, issue.fixed_version_id
1075 end
1090 end
1076
1091
1077 def test_move_to_another_project_should_keep_parent_if_valid
1092 def test_move_to_another_project_should_keep_parent_if_valid
1078 issue = Issue.find(1)
1093 issue = Issue.find(1)
1079 issue.update_attribute(:parent_issue_id, 2)
1094 issue.update_attribute(:parent_issue_id, 2)
1080 issue.project = Project.find(3)
1095 issue.project = Project.find(3)
1081 assert issue.save
1096 assert issue.save
1082 issue.reload
1097 issue.reload
1083 assert_equal 2, issue.parent_id
1098 assert_equal 2, issue.parent_id
1084 end
1099 end
1085
1100
1086 def test_move_to_another_project_should_clear_parent_if_not_valid
1101 def test_move_to_another_project_should_clear_parent_if_not_valid
1087 issue = Issue.find(1)
1102 issue = Issue.find(1)
1088 issue.update_attribute(:parent_issue_id, 2)
1103 issue.update_attribute(:parent_issue_id, 2)
1089 issue.project = Project.find(2)
1104 issue.project = Project.find(2)
1090 assert issue.save
1105 assert issue.save
1091 issue.reload
1106 issue.reload
1092 assert_nil issue.parent_id
1107 assert_nil issue.parent_id
1093 end
1108 end
1094
1109
1095 def test_move_to_another_project_with_disabled_tracker
1110 def test_move_to_another_project_with_disabled_tracker
1096 issue = Issue.find(1)
1111 issue = Issue.find(1)
1097 target = Project.find(2)
1112 target = Project.find(2)
1098 target.tracker_ids = [3]
1113 target.tracker_ids = [3]
1099 target.save
1114 target.save
1100 issue.project = target
1115 issue.project = target
1101 assert issue.save
1116 assert issue.save
1102 issue.reload
1117 issue.reload
1103 assert_equal 2, issue.project_id
1118 assert_equal 2, issue.project_id
1104 assert_equal 3, issue.tracker_id
1119 assert_equal 3, issue.tracker_id
1105 end
1120 end
1106
1121
1107 def test_copy_to_the_same_project
1122 def test_copy_to_the_same_project
1108 issue = Issue.find(1)
1123 issue = Issue.find(1)
1109 copy = issue.copy
1124 copy = issue.copy
1110 assert_difference 'Issue.count' do
1125 assert_difference 'Issue.count' do
1111 copy.save!
1126 copy.save!
1112 end
1127 end
1113 assert_kind_of Issue, copy
1128 assert_kind_of Issue, copy
1114 assert_equal issue.project, copy.project
1129 assert_equal issue.project, copy.project
1115 assert_equal "125", copy.custom_value_for(2).value
1130 assert_equal "125", copy.custom_value_for(2).value
1116 end
1131 end
1117
1132
1118 def test_copy_to_another_project_and_tracker
1133 def test_copy_to_another_project_and_tracker
1119 issue = Issue.find(1)
1134 issue = Issue.find(1)
1120 copy = issue.copy(:project_id => 3, :tracker_id => 2)
1135 copy = issue.copy(:project_id => 3, :tracker_id => 2)
1121 assert_difference 'Issue.count' do
1136 assert_difference 'Issue.count' do
1122 copy.save!
1137 copy.save!
1123 end
1138 end
1124 copy.reload
1139 copy.reload
1125 assert_kind_of Issue, copy
1140 assert_kind_of Issue, copy
1126 assert_equal Project.find(3), copy.project
1141 assert_equal Project.find(3), copy.project
1127 assert_equal Tracker.find(2), copy.tracker
1142 assert_equal Tracker.find(2), copy.tracker
1128 # Custom field #2 is not associated with target tracker
1143 # Custom field #2 is not associated with target tracker
1129 assert_nil copy.custom_value_for(2)
1144 assert_nil copy.custom_value_for(2)
1130 end
1145 end
1131
1146
1132 test "#copy should not create a journal" do
1147 test "#copy should not create a journal" do
1133 copy = Issue.find(1).copy(:project_id => 3, :tracker_id => 2, :assigned_to_id => 3)
1148 copy = Issue.find(1).copy(:project_id => 3, :tracker_id => 2, :assigned_to_id => 3)
1134 copy.save!
1149 copy.save!
1135 assert_equal 0, copy.reload.journals.size
1150 assert_equal 0, copy.reload.journals.size
1136 end
1151 end
1137
1152
1138 test "#copy should allow assigned_to changes" do
1153 test "#copy should allow assigned_to changes" do
1139 copy = Issue.find(1).copy(:project_id => 3, :tracker_id => 2, :assigned_to_id => 3)
1154 copy = Issue.find(1).copy(:project_id => 3, :tracker_id => 2, :assigned_to_id => 3)
1140 assert_equal 3, copy.assigned_to_id
1155 assert_equal 3, copy.assigned_to_id
1141 end
1156 end
1142
1157
1143 test "#copy should allow status changes" do
1158 test "#copy should allow status changes" do
1144 copy = Issue.find(1).copy(:project_id => 3, :tracker_id => 2, :status_id => 2)
1159 copy = Issue.find(1).copy(:project_id => 3, :tracker_id => 2, :status_id => 2)
1145 assert_equal 2, copy.status_id
1160 assert_equal 2, copy.status_id
1146 end
1161 end
1147
1162
1148 test "#copy should allow start date changes" do
1163 test "#copy should allow start date changes" do
1149 date = Date.today
1164 date = Date.today
1150 copy = Issue.find(1).copy(:project_id => 3, :tracker_id => 2, :start_date => date)
1165 copy = Issue.find(1).copy(:project_id => 3, :tracker_id => 2, :start_date => date)
1151 assert_equal date, copy.start_date
1166 assert_equal date, copy.start_date
1152 end
1167 end
1153
1168
1154 test "#copy should allow due date changes" do
1169 test "#copy should allow due date changes" do
1155 date = Date.today
1170 date = Date.today
1156 copy = Issue.find(1).copy(:project_id => 3, :tracker_id => 2, :due_date => date)
1171 copy = Issue.find(1).copy(:project_id => 3, :tracker_id => 2, :due_date => date)
1157 assert_equal date, copy.due_date
1172 assert_equal date, copy.due_date
1158 end
1173 end
1159
1174
1160 test "#copy should set current user as author" do
1175 test "#copy should set current user as author" do
1161 User.current = User.find(9)
1176 User.current = User.find(9)
1162 copy = Issue.find(1).copy(:project_id => 3, :tracker_id => 2)
1177 copy = Issue.find(1).copy(:project_id => 3, :tracker_id => 2)
1163 assert_equal User.current, copy.author
1178 assert_equal User.current, copy.author
1164 end
1179 end
1165
1180
1166 test "#copy should create a journal with notes" do
1181 test "#copy should create a journal with notes" do
1167 date = Date.today
1182 date = Date.today
1168 notes = "Notes added when copying"
1183 notes = "Notes added when copying"
1169 copy = Issue.find(1).copy(:project_id => 3, :tracker_id => 2, :start_date => date)
1184 copy = Issue.find(1).copy(:project_id => 3, :tracker_id => 2, :start_date => date)
1170 copy.init_journal(User.current, notes)
1185 copy.init_journal(User.current, notes)
1171 copy.save!
1186 copy.save!
1172
1187
1173 assert_equal 1, copy.journals.size
1188 assert_equal 1, copy.journals.size
1174 journal = copy.journals.first
1189 journal = copy.journals.first
1175 assert_equal 0, journal.details.size
1190 assert_equal 0, journal.details.size
1176 assert_equal notes, journal.notes
1191 assert_equal notes, journal.notes
1177 end
1192 end
1178
1193
1179 def test_valid_parent_project
1194 def test_valid_parent_project
1180 issue = Issue.find(1)
1195 issue = Issue.find(1)
1181 issue_in_same_project = Issue.find(2)
1196 issue_in_same_project = Issue.find(2)
1182 issue_in_child_project = Issue.find(5)
1197 issue_in_child_project = Issue.find(5)
1183 issue_in_grandchild_project = Issue.generate!(:project_id => 6, :tracker_id => 1)
1198 issue_in_grandchild_project = Issue.generate!(:project_id => 6, :tracker_id => 1)
1184 issue_in_other_child_project = Issue.find(6)
1199 issue_in_other_child_project = Issue.find(6)
1185 issue_in_different_tree = Issue.find(4)
1200 issue_in_different_tree = Issue.find(4)
1186
1201
1187 with_settings :cross_project_subtasks => '' do
1202 with_settings :cross_project_subtasks => '' do
1188 assert_equal true, issue.valid_parent_project?(issue_in_same_project)
1203 assert_equal true, issue.valid_parent_project?(issue_in_same_project)
1189 assert_equal false, issue.valid_parent_project?(issue_in_child_project)
1204 assert_equal false, issue.valid_parent_project?(issue_in_child_project)
1190 assert_equal false, issue.valid_parent_project?(issue_in_grandchild_project)
1205 assert_equal false, issue.valid_parent_project?(issue_in_grandchild_project)
1191 assert_equal false, issue.valid_parent_project?(issue_in_different_tree)
1206 assert_equal false, issue.valid_parent_project?(issue_in_different_tree)
1192 end
1207 end
1193
1208
1194 with_settings :cross_project_subtasks => 'system' do
1209 with_settings :cross_project_subtasks => 'system' do
1195 assert_equal true, issue.valid_parent_project?(issue_in_same_project)
1210 assert_equal true, issue.valid_parent_project?(issue_in_same_project)
1196 assert_equal true, issue.valid_parent_project?(issue_in_child_project)
1211 assert_equal true, issue.valid_parent_project?(issue_in_child_project)
1197 assert_equal true, issue.valid_parent_project?(issue_in_different_tree)
1212 assert_equal true, issue.valid_parent_project?(issue_in_different_tree)
1198 end
1213 end
1199
1214
1200 with_settings :cross_project_subtasks => 'tree' do
1215 with_settings :cross_project_subtasks => 'tree' do
1201 assert_equal true, issue.valid_parent_project?(issue_in_same_project)
1216 assert_equal true, issue.valid_parent_project?(issue_in_same_project)
1202 assert_equal true, issue.valid_parent_project?(issue_in_child_project)
1217 assert_equal true, issue.valid_parent_project?(issue_in_child_project)
1203 assert_equal true, issue.valid_parent_project?(issue_in_grandchild_project)
1218 assert_equal true, issue.valid_parent_project?(issue_in_grandchild_project)
1204 assert_equal false, issue.valid_parent_project?(issue_in_different_tree)
1219 assert_equal false, issue.valid_parent_project?(issue_in_different_tree)
1205
1220
1206 assert_equal true, issue_in_child_project.valid_parent_project?(issue_in_same_project)
1221 assert_equal true, issue_in_child_project.valid_parent_project?(issue_in_same_project)
1207 assert_equal true, issue_in_child_project.valid_parent_project?(issue_in_other_child_project)
1222 assert_equal true, issue_in_child_project.valid_parent_project?(issue_in_other_child_project)
1208 end
1223 end
1209
1224
1210 with_settings :cross_project_subtasks => 'descendants' do
1225 with_settings :cross_project_subtasks => 'descendants' do
1211 assert_equal true, issue.valid_parent_project?(issue_in_same_project)
1226 assert_equal true, issue.valid_parent_project?(issue_in_same_project)
1212 assert_equal false, issue.valid_parent_project?(issue_in_child_project)
1227 assert_equal false, issue.valid_parent_project?(issue_in_child_project)
1213 assert_equal false, issue.valid_parent_project?(issue_in_grandchild_project)
1228 assert_equal false, issue.valid_parent_project?(issue_in_grandchild_project)
1214 assert_equal false, issue.valid_parent_project?(issue_in_different_tree)
1229 assert_equal false, issue.valid_parent_project?(issue_in_different_tree)
1215
1230
1216 assert_equal true, issue_in_child_project.valid_parent_project?(issue)
1231 assert_equal true, issue_in_child_project.valid_parent_project?(issue)
1217 assert_equal false, issue_in_child_project.valid_parent_project?(issue_in_other_child_project)
1232 assert_equal false, issue_in_child_project.valid_parent_project?(issue_in_other_child_project)
1218 end
1233 end
1219 end
1234 end
1220
1235
1221 def test_recipients_should_include_previous_assignee
1236 def test_recipients_should_include_previous_assignee
1222 user = User.find(3)
1237 user = User.find(3)
1223 user.members.update_all ["mail_notification = ?", false]
1238 user.members.update_all ["mail_notification = ?", false]
1224 user.update_attribute :mail_notification, 'only_assigned'
1239 user.update_attribute :mail_notification, 'only_assigned'
1225
1240
1226 issue = Issue.find(2)
1241 issue = Issue.find(2)
1227 issue.assigned_to = nil
1242 issue.assigned_to = nil
1228 assert_include user.mail, issue.recipients
1243 assert_include user.mail, issue.recipients
1229 issue.save!
1244 issue.save!
1230 assert !issue.recipients.include?(user.mail)
1245 assert !issue.recipients.include?(user.mail)
1231 end
1246 end
1232
1247
1233 def test_recipients_should_not_include_users_that_cannot_view_the_issue
1248 def test_recipients_should_not_include_users_that_cannot_view_the_issue
1234 issue = Issue.find(12)
1249 issue = Issue.find(12)
1235 assert issue.recipients.include?(issue.author.mail)
1250 assert issue.recipients.include?(issue.author.mail)
1236 # copy the issue to a private project
1251 # copy the issue to a private project
1237 copy = issue.copy(:project_id => 5, :tracker_id => 2)
1252 copy = issue.copy(:project_id => 5, :tracker_id => 2)
1238 # author is not a member of project anymore
1253 # author is not a member of project anymore
1239 assert !copy.recipients.include?(copy.author.mail)
1254 assert !copy.recipients.include?(copy.author.mail)
1240 end
1255 end
1241
1256
1242 def test_recipients_should_include_the_assigned_group_members
1257 def test_recipients_should_include_the_assigned_group_members
1243 group_member = User.generate!
1258 group_member = User.generate!
1244 group = Group.generate!
1259 group = Group.generate!
1245 group.users << group_member
1260 group.users << group_member
1246
1261
1247 issue = Issue.find(12)
1262 issue = Issue.find(12)
1248 issue.assigned_to = group
1263 issue.assigned_to = group
1249 assert issue.recipients.include?(group_member.mail)
1264 assert issue.recipients.include?(group_member.mail)
1250 end
1265 end
1251
1266
1252 def test_watcher_recipients_should_not_include_users_that_cannot_view_the_issue
1267 def test_watcher_recipients_should_not_include_users_that_cannot_view_the_issue
1253 user = User.find(3)
1268 user = User.find(3)
1254 issue = Issue.find(9)
1269 issue = Issue.find(9)
1255 Watcher.create!(:user => user, :watchable => issue)
1270 Watcher.create!(:user => user, :watchable => issue)
1256 assert issue.watched_by?(user)
1271 assert issue.watched_by?(user)
1257 assert !issue.watcher_recipients.include?(user.mail)
1272 assert !issue.watcher_recipients.include?(user.mail)
1258 end
1273 end
1259
1274
1260 def test_issue_destroy
1275 def test_issue_destroy
1261 Issue.find(1).destroy
1276 Issue.find(1).destroy
1262 assert_nil Issue.find_by_id(1)
1277 assert_nil Issue.find_by_id(1)
1263 assert_nil TimeEntry.find_by_issue_id(1)
1278 assert_nil TimeEntry.find_by_issue_id(1)
1264 end
1279 end
1265
1280
1266 def test_destroying_a_deleted_issue_should_not_raise_an_error
1281 def test_destroying_a_deleted_issue_should_not_raise_an_error
1267 issue = Issue.find(1)
1282 issue = Issue.find(1)
1268 Issue.find(1).destroy
1283 Issue.find(1).destroy
1269
1284
1270 assert_nothing_raised do
1285 assert_nothing_raised do
1271 assert_no_difference 'Issue.count' do
1286 assert_no_difference 'Issue.count' do
1272 issue.destroy
1287 issue.destroy
1273 end
1288 end
1274 assert issue.destroyed?
1289 assert issue.destroyed?
1275 end
1290 end
1276 end
1291 end
1277
1292
1278 def test_destroying_a_stale_issue_should_not_raise_an_error
1293 def test_destroying_a_stale_issue_should_not_raise_an_error
1279 issue = Issue.find(1)
1294 issue = Issue.find(1)
1280 Issue.find(1).update_attribute :subject, "Updated"
1295 Issue.find(1).update_attribute :subject, "Updated"
1281
1296
1282 assert_nothing_raised do
1297 assert_nothing_raised do
1283 assert_difference 'Issue.count', -1 do
1298 assert_difference 'Issue.count', -1 do
1284 issue.destroy
1299 issue.destroy
1285 end
1300 end
1286 assert issue.destroyed?
1301 assert issue.destroyed?
1287 end
1302 end
1288 end
1303 end
1289
1304
1290 def test_blocked
1305 def test_blocked
1291 blocked_issue = Issue.find(9)
1306 blocked_issue = Issue.find(9)
1292 blocking_issue = Issue.find(10)
1307 blocking_issue = Issue.find(10)
1293
1308
1294 assert blocked_issue.blocked?
1309 assert blocked_issue.blocked?
1295 assert !blocking_issue.blocked?
1310 assert !blocking_issue.blocked?
1296 end
1311 end
1297
1312
1298 def test_blocked_issues_dont_allow_closed_statuses
1313 def test_blocked_issues_dont_allow_closed_statuses
1299 blocked_issue = Issue.find(9)
1314 blocked_issue = Issue.find(9)
1300
1315
1301 allowed_statuses = blocked_issue.new_statuses_allowed_to(users(:users_002))
1316 allowed_statuses = blocked_issue.new_statuses_allowed_to(users(:users_002))
1302 assert !allowed_statuses.empty?
1317 assert !allowed_statuses.empty?
1303 closed_statuses = allowed_statuses.select {|st| st.is_closed?}
1318 closed_statuses = allowed_statuses.select {|st| st.is_closed?}
1304 assert closed_statuses.empty?
1319 assert closed_statuses.empty?
1305 end
1320 end
1306
1321
1307 def test_unblocked_issues_allow_closed_statuses
1322 def test_unblocked_issues_allow_closed_statuses
1308 blocking_issue = Issue.find(10)
1323 blocking_issue = Issue.find(10)
1309
1324
1310 allowed_statuses = blocking_issue.new_statuses_allowed_to(users(:users_002))
1325 allowed_statuses = blocking_issue.new_statuses_allowed_to(users(:users_002))
1311 assert !allowed_statuses.empty?
1326 assert !allowed_statuses.empty?
1312 closed_statuses = allowed_statuses.select {|st| st.is_closed?}
1327 closed_statuses = allowed_statuses.select {|st| st.is_closed?}
1313 assert !closed_statuses.empty?
1328 assert !closed_statuses.empty?
1314 end
1329 end
1315
1330
1316 def test_reschedule_an_issue_without_dates
1331 def test_reschedule_an_issue_without_dates
1317 with_settings :non_working_week_days => [] do
1332 with_settings :non_working_week_days => [] do
1318 issue = Issue.new(:start_date => nil, :due_date => nil)
1333 issue = Issue.new(:start_date => nil, :due_date => nil)
1319 issue.reschedule_on '2012-10-09'.to_date
1334 issue.reschedule_on '2012-10-09'.to_date
1320 assert_equal '2012-10-09'.to_date, issue.start_date
1335 assert_equal '2012-10-09'.to_date, issue.start_date
1321 assert_equal '2012-10-09'.to_date, issue.due_date
1336 assert_equal '2012-10-09'.to_date, issue.due_date
1322 end
1337 end
1323
1338
1324 with_settings :non_working_week_days => %w(6 7) do
1339 with_settings :non_working_week_days => %w(6 7) do
1325 issue = Issue.new(:start_date => nil, :due_date => nil)
1340 issue = Issue.new(:start_date => nil, :due_date => nil)
1326 issue.reschedule_on '2012-10-09'.to_date
1341 issue.reschedule_on '2012-10-09'.to_date
1327 assert_equal '2012-10-09'.to_date, issue.start_date
1342 assert_equal '2012-10-09'.to_date, issue.start_date
1328 assert_equal '2012-10-09'.to_date, issue.due_date
1343 assert_equal '2012-10-09'.to_date, issue.due_date
1329
1344
1330 issue = Issue.new(:start_date => nil, :due_date => nil)
1345 issue = Issue.new(:start_date => nil, :due_date => nil)
1331 issue.reschedule_on '2012-10-13'.to_date
1346 issue.reschedule_on '2012-10-13'.to_date
1332 assert_equal '2012-10-15'.to_date, issue.start_date
1347 assert_equal '2012-10-15'.to_date, issue.start_date
1333 assert_equal '2012-10-15'.to_date, issue.due_date
1348 assert_equal '2012-10-15'.to_date, issue.due_date
1334 end
1349 end
1335 end
1350 end
1336
1351
1337 def test_reschedule_an_issue_with_start_date
1352 def test_reschedule_an_issue_with_start_date
1338 with_settings :non_working_week_days => [] do
1353 with_settings :non_working_week_days => [] do
1339 issue = Issue.new(:start_date => '2012-10-09', :due_date => nil)
1354 issue = Issue.new(:start_date => '2012-10-09', :due_date => nil)
1340 issue.reschedule_on '2012-10-13'.to_date
1355 issue.reschedule_on '2012-10-13'.to_date
1341 assert_equal '2012-10-13'.to_date, issue.start_date
1356 assert_equal '2012-10-13'.to_date, issue.start_date
1342 assert_equal '2012-10-13'.to_date, issue.due_date
1357 assert_equal '2012-10-13'.to_date, issue.due_date
1343 end
1358 end
1344
1359
1345 with_settings :non_working_week_days => %w(6 7) do
1360 with_settings :non_working_week_days => %w(6 7) do
1346 issue = Issue.new(:start_date => '2012-10-09', :due_date => nil)
1361 issue = Issue.new(:start_date => '2012-10-09', :due_date => nil)
1347 issue.reschedule_on '2012-10-11'.to_date
1362 issue.reschedule_on '2012-10-11'.to_date
1348 assert_equal '2012-10-11'.to_date, issue.start_date
1363 assert_equal '2012-10-11'.to_date, issue.start_date
1349 assert_equal '2012-10-11'.to_date, issue.due_date
1364 assert_equal '2012-10-11'.to_date, issue.due_date
1350
1365
1351 issue = Issue.new(:start_date => '2012-10-09', :due_date => nil)
1366 issue = Issue.new(:start_date => '2012-10-09', :due_date => nil)
1352 issue.reschedule_on '2012-10-13'.to_date
1367 issue.reschedule_on '2012-10-13'.to_date
1353 assert_equal '2012-10-15'.to_date, issue.start_date
1368 assert_equal '2012-10-15'.to_date, issue.start_date
1354 assert_equal '2012-10-15'.to_date, issue.due_date
1369 assert_equal '2012-10-15'.to_date, issue.due_date
1355 end
1370 end
1356 end
1371 end
1357
1372
1358 def test_reschedule_an_issue_with_start_and_due_dates
1373 def test_reschedule_an_issue_with_start_and_due_dates
1359 with_settings :non_working_week_days => [] do
1374 with_settings :non_working_week_days => [] do
1360 issue = Issue.new(:start_date => '2012-10-09', :due_date => '2012-10-15')
1375 issue = Issue.new(:start_date => '2012-10-09', :due_date => '2012-10-15')
1361 issue.reschedule_on '2012-10-13'.to_date
1376 issue.reschedule_on '2012-10-13'.to_date
1362 assert_equal '2012-10-13'.to_date, issue.start_date
1377 assert_equal '2012-10-13'.to_date, issue.start_date
1363 assert_equal '2012-10-19'.to_date, issue.due_date
1378 assert_equal '2012-10-19'.to_date, issue.due_date
1364 end
1379 end
1365
1380
1366 with_settings :non_working_week_days => %w(6 7) do
1381 with_settings :non_working_week_days => %w(6 7) do
1367 issue = Issue.new(:start_date => '2012-10-09', :due_date => '2012-10-19') # 8 working days
1382 issue = Issue.new(:start_date => '2012-10-09', :due_date => '2012-10-19') # 8 working days
1368 issue.reschedule_on '2012-10-11'.to_date
1383 issue.reschedule_on '2012-10-11'.to_date
1369 assert_equal '2012-10-11'.to_date, issue.start_date
1384 assert_equal '2012-10-11'.to_date, issue.start_date
1370 assert_equal '2012-10-23'.to_date, issue.due_date
1385 assert_equal '2012-10-23'.to_date, issue.due_date
1371
1386
1372 issue = Issue.new(:start_date => '2012-10-09', :due_date => '2012-10-19')
1387 issue = Issue.new(:start_date => '2012-10-09', :due_date => '2012-10-19')
1373 issue.reschedule_on '2012-10-13'.to_date
1388 issue.reschedule_on '2012-10-13'.to_date
1374 assert_equal '2012-10-15'.to_date, issue.start_date
1389 assert_equal '2012-10-15'.to_date, issue.start_date
1375 assert_equal '2012-10-25'.to_date, issue.due_date
1390 assert_equal '2012-10-25'.to_date, issue.due_date
1376 end
1391 end
1377 end
1392 end
1378
1393
1379 def test_rescheduling_an_issue_to_a_later_due_date_should_reschedule_following_issue
1394 def test_rescheduling_an_issue_to_a_later_due_date_should_reschedule_following_issue
1380 issue1 = Issue.generate!(:start_date => '2012-10-15', :due_date => '2012-10-17')
1395 issue1 = Issue.generate!(:start_date => '2012-10-15', :due_date => '2012-10-17')
1381 issue2 = Issue.generate!(:start_date => '2012-10-15', :due_date => '2012-10-17')
1396 issue2 = Issue.generate!(:start_date => '2012-10-15', :due_date => '2012-10-17')
1382 IssueRelation.create!(:issue_from => issue1, :issue_to => issue2,
1397 IssueRelation.create!(:issue_from => issue1, :issue_to => issue2,
1383 :relation_type => IssueRelation::TYPE_PRECEDES)
1398 :relation_type => IssueRelation::TYPE_PRECEDES)
1384 assert_equal Date.parse('2012-10-18'), issue2.reload.start_date
1399 assert_equal Date.parse('2012-10-18'), issue2.reload.start_date
1385
1400
1386 issue1.due_date = '2012-10-23'
1401 issue1.due_date = '2012-10-23'
1387 issue1.save!
1402 issue1.save!
1388 issue2.reload
1403 issue2.reload
1389 assert_equal Date.parse('2012-10-24'), issue2.start_date
1404 assert_equal Date.parse('2012-10-24'), issue2.start_date
1390 assert_equal Date.parse('2012-10-26'), issue2.due_date
1405 assert_equal Date.parse('2012-10-26'), issue2.due_date
1391 end
1406 end
1392
1407
1393 def test_rescheduling_an_issue_to_an_earlier_due_date_should_reschedule_following_issue
1408 def test_rescheduling_an_issue_to_an_earlier_due_date_should_reschedule_following_issue
1394 issue1 = Issue.generate!(:start_date => '2012-10-15', :due_date => '2012-10-17')
1409 issue1 = Issue.generate!(:start_date => '2012-10-15', :due_date => '2012-10-17')
1395 issue2 = Issue.generate!(:start_date => '2012-10-15', :due_date => '2012-10-17')
1410 issue2 = Issue.generate!(:start_date => '2012-10-15', :due_date => '2012-10-17')
1396 IssueRelation.create!(:issue_from => issue1, :issue_to => issue2,
1411 IssueRelation.create!(:issue_from => issue1, :issue_to => issue2,
1397 :relation_type => IssueRelation::TYPE_PRECEDES)
1412 :relation_type => IssueRelation::TYPE_PRECEDES)
1398 assert_equal Date.parse('2012-10-18'), issue2.reload.start_date
1413 assert_equal Date.parse('2012-10-18'), issue2.reload.start_date
1399
1414
1400 issue1.start_date = '2012-09-17'
1415 issue1.start_date = '2012-09-17'
1401 issue1.due_date = '2012-09-18'
1416 issue1.due_date = '2012-09-18'
1402 issue1.save!
1417 issue1.save!
1403 issue2.reload
1418 issue2.reload
1404 assert_equal Date.parse('2012-09-19'), issue2.start_date
1419 assert_equal Date.parse('2012-09-19'), issue2.start_date
1405 assert_equal Date.parse('2012-09-21'), issue2.due_date
1420 assert_equal Date.parse('2012-09-21'), issue2.due_date
1406 end
1421 end
1407
1422
1408 def test_rescheduling_reschedule_following_issue_earlier_should_consider_other_preceding_issues
1423 def test_rescheduling_reschedule_following_issue_earlier_should_consider_other_preceding_issues
1409 issue1 = Issue.generate!(:start_date => '2012-10-15', :due_date => '2012-10-17')
1424 issue1 = Issue.generate!(:start_date => '2012-10-15', :due_date => '2012-10-17')
1410 issue2 = Issue.generate!(:start_date => '2012-10-15', :due_date => '2012-10-17')
1425 issue2 = Issue.generate!(:start_date => '2012-10-15', :due_date => '2012-10-17')
1411 issue3 = Issue.generate!(:start_date => '2012-10-01', :due_date => '2012-10-02')
1426 issue3 = Issue.generate!(:start_date => '2012-10-01', :due_date => '2012-10-02')
1412 IssueRelation.create!(:issue_from => issue1, :issue_to => issue2,
1427 IssueRelation.create!(:issue_from => issue1, :issue_to => issue2,
1413 :relation_type => IssueRelation::TYPE_PRECEDES)
1428 :relation_type => IssueRelation::TYPE_PRECEDES)
1414 IssueRelation.create!(:issue_from => issue3, :issue_to => issue2,
1429 IssueRelation.create!(:issue_from => issue3, :issue_to => issue2,
1415 :relation_type => IssueRelation::TYPE_PRECEDES)
1430 :relation_type => IssueRelation::TYPE_PRECEDES)
1416 assert_equal Date.parse('2012-10-18'), issue2.reload.start_date
1431 assert_equal Date.parse('2012-10-18'), issue2.reload.start_date
1417
1432
1418 issue1.start_date = '2012-09-17'
1433 issue1.start_date = '2012-09-17'
1419 issue1.due_date = '2012-09-18'
1434 issue1.due_date = '2012-09-18'
1420 issue1.save!
1435 issue1.save!
1421 issue2.reload
1436 issue2.reload
1422 # Issue 2 must start after Issue 3
1437 # Issue 2 must start after Issue 3
1423 assert_equal Date.parse('2012-10-03'), issue2.start_date
1438 assert_equal Date.parse('2012-10-03'), issue2.start_date
1424 assert_equal Date.parse('2012-10-05'), issue2.due_date
1439 assert_equal Date.parse('2012-10-05'), issue2.due_date
1425 end
1440 end
1426
1441
1427 def test_rescheduling_a_stale_issue_should_not_raise_an_error
1442 def test_rescheduling_a_stale_issue_should_not_raise_an_error
1428 with_settings :non_working_week_days => [] do
1443 with_settings :non_working_week_days => [] do
1429 stale = Issue.find(1)
1444 stale = Issue.find(1)
1430 issue = Issue.find(1)
1445 issue = Issue.find(1)
1431 issue.subject = "Updated"
1446 issue.subject = "Updated"
1432 issue.save!
1447 issue.save!
1433 date = 10.days.from_now.to_date
1448 date = 10.days.from_now.to_date
1434 assert_nothing_raised do
1449 assert_nothing_raised do
1435 stale.reschedule_on!(date)
1450 stale.reschedule_on!(date)
1436 end
1451 end
1437 assert_equal date, stale.reload.start_date
1452 assert_equal date, stale.reload.start_date
1438 end
1453 end
1439 end
1454 end
1440
1455
1441 def test_overdue
1456 def test_overdue
1442 assert Issue.new(:due_date => 1.day.ago.to_date).overdue?
1457 assert Issue.new(:due_date => 1.day.ago.to_date).overdue?
1443 assert !Issue.new(:due_date => Date.today).overdue?
1458 assert !Issue.new(:due_date => Date.today).overdue?
1444 assert !Issue.new(:due_date => 1.day.from_now.to_date).overdue?
1459 assert !Issue.new(:due_date => 1.day.from_now.to_date).overdue?
1445 assert !Issue.new(:due_date => nil).overdue?
1460 assert !Issue.new(:due_date => nil).overdue?
1446 assert !Issue.new(:due_date => 1.day.ago.to_date,
1461 assert !Issue.new(:due_date => 1.day.ago.to_date,
1447 :status => IssueStatus.where(:is_closed => true).first
1462 :status => IssueStatus.where(:is_closed => true).first
1448 ).overdue?
1463 ).overdue?
1449 end
1464 end
1450
1465
1451 test "#behind_schedule? should be false if the issue has no start_date" do
1466 test "#behind_schedule? should be false if the issue has no start_date" do
1452 assert !Issue.new(:start_date => nil,
1467 assert !Issue.new(:start_date => nil,
1453 :due_date => 1.day.from_now.to_date,
1468 :due_date => 1.day.from_now.to_date,
1454 :done_ratio => 0).behind_schedule?
1469 :done_ratio => 0).behind_schedule?
1455 end
1470 end
1456
1471
1457 test "#behind_schedule? should be false if the issue has no end_date" do
1472 test "#behind_schedule? should be false if the issue has no end_date" do
1458 assert !Issue.new(:start_date => 1.day.from_now.to_date,
1473 assert !Issue.new(:start_date => 1.day.from_now.to_date,
1459 :due_date => nil,
1474 :due_date => nil,
1460 :done_ratio => 0).behind_schedule?
1475 :done_ratio => 0).behind_schedule?
1461 end
1476 end
1462
1477
1463 test "#behind_schedule? should be false if the issue has more done than it's calendar time" do
1478 test "#behind_schedule? should be false if the issue has more done than it's calendar time" do
1464 assert !Issue.new(:start_date => 50.days.ago.to_date,
1479 assert !Issue.new(:start_date => 50.days.ago.to_date,
1465 :due_date => 50.days.from_now.to_date,
1480 :due_date => 50.days.from_now.to_date,
1466 :done_ratio => 90).behind_schedule?
1481 :done_ratio => 90).behind_schedule?
1467 end
1482 end
1468
1483
1469 test "#behind_schedule? should be true if the issue hasn't been started at all" do
1484 test "#behind_schedule? should be true if the issue hasn't been started at all" do
1470 assert Issue.new(:start_date => 1.day.ago.to_date,
1485 assert Issue.new(:start_date => 1.day.ago.to_date,
1471 :due_date => 1.day.from_now.to_date,
1486 :due_date => 1.day.from_now.to_date,
1472 :done_ratio => 0).behind_schedule?
1487 :done_ratio => 0).behind_schedule?
1473 end
1488 end
1474
1489
1475 test "#behind_schedule? should be true if the issue has used more calendar time than it's done ratio" do
1490 test "#behind_schedule? should be true if the issue has used more calendar time than it's done ratio" do
1476 assert Issue.new(:start_date => 100.days.ago.to_date,
1491 assert Issue.new(:start_date => 100.days.ago.to_date,
1477 :due_date => Date.today,
1492 :due_date => Date.today,
1478 :done_ratio => 90).behind_schedule?
1493 :done_ratio => 90).behind_schedule?
1479 end
1494 end
1480
1495
1481 test "#assignable_users should be Users" do
1496 test "#assignable_users should be Users" do
1482 assert_kind_of User, Issue.find(1).assignable_users.first
1497 assert_kind_of User, Issue.find(1).assignable_users.first
1483 end
1498 end
1484
1499
1485 test "#assignable_users should include the issue author" do
1500 test "#assignable_users should include the issue author" do
1486 non_project_member = User.generate!
1501 non_project_member = User.generate!
1487 issue = Issue.generate!(:author => non_project_member)
1502 issue = Issue.generate!(:author => non_project_member)
1488
1503
1489 assert issue.assignable_users.include?(non_project_member)
1504 assert issue.assignable_users.include?(non_project_member)
1490 end
1505 end
1491
1506
1492 test "#assignable_users should include the current assignee" do
1507 test "#assignable_users should include the current assignee" do
1493 user = User.generate!
1508 user = User.generate!
1494 issue = Issue.generate!(:assigned_to => user)
1509 issue = Issue.generate!(:assigned_to => user)
1495 user.lock!
1510 user.lock!
1496
1511
1497 assert Issue.find(issue.id).assignable_users.include?(user)
1512 assert Issue.find(issue.id).assignable_users.include?(user)
1498 end
1513 end
1499
1514
1500 test "#assignable_users should not show the issue author twice" do
1515 test "#assignable_users should not show the issue author twice" do
1501 assignable_user_ids = Issue.find(1).assignable_users.collect(&:id)
1516 assignable_user_ids = Issue.find(1).assignable_users.collect(&:id)
1502 assert_equal 2, assignable_user_ids.length
1517 assert_equal 2, assignable_user_ids.length
1503
1518
1504 assignable_user_ids.each do |user_id|
1519 assignable_user_ids.each do |user_id|
1505 assert_equal 1, assignable_user_ids.select {|i| i == user_id}.length,
1520 assert_equal 1, assignable_user_ids.select {|i| i == user_id}.length,
1506 "User #{user_id} appears more or less than once"
1521 "User #{user_id} appears more or less than once"
1507 end
1522 end
1508 end
1523 end
1509
1524
1510 test "#assignable_users with issue_group_assignment should include groups" do
1525 test "#assignable_users with issue_group_assignment should include groups" do
1511 issue = Issue.new(:project => Project.find(2))
1526 issue = Issue.new(:project => Project.find(2))
1512
1527
1513 with_settings :issue_group_assignment => '1' do
1528 with_settings :issue_group_assignment => '1' do
1514 assert_equal %w(Group User), issue.assignable_users.map {|a| a.class.name}.uniq.sort
1529 assert_equal %w(Group User), issue.assignable_users.map {|a| a.class.name}.uniq.sort
1515 assert issue.assignable_users.include?(Group.find(11))
1530 assert issue.assignable_users.include?(Group.find(11))
1516 end
1531 end
1517 end
1532 end
1518
1533
1519 test "#assignable_users without issue_group_assignment should not include groups" do
1534 test "#assignable_users without issue_group_assignment should not include groups" do
1520 issue = Issue.new(:project => Project.find(2))
1535 issue = Issue.new(:project => Project.find(2))
1521
1536
1522 with_settings :issue_group_assignment => '0' do
1537 with_settings :issue_group_assignment => '0' do
1523 assert_equal %w(User), issue.assignable_users.map {|a| a.class.name}.uniq.sort
1538 assert_equal %w(User), issue.assignable_users.map {|a| a.class.name}.uniq.sort
1524 assert !issue.assignable_users.include?(Group.find(11))
1539 assert !issue.assignable_users.include?(Group.find(11))
1525 end
1540 end
1526 end
1541 end
1527
1542
1528 def test_create_should_send_email_notification
1543 def test_create_should_send_email_notification
1529 ActionMailer::Base.deliveries.clear
1544 ActionMailer::Base.deliveries.clear
1530 issue = Issue.new(:project_id => 1, :tracker_id => 1,
1545 issue = Issue.new(:project_id => 1, :tracker_id => 1,
1531 :author_id => 3, :status_id => 1,
1546 :author_id => 3, :status_id => 1,
1532 :priority => IssuePriority.all.first,
1547 :priority => IssuePriority.all.first,
1533 :subject => 'test_create', :estimated_hours => '1:30')
1548 :subject => 'test_create', :estimated_hours => '1:30')
1534
1549
1535 assert issue.save
1550 assert issue.save
1536 assert_equal 1, ActionMailer::Base.deliveries.size
1551 assert_equal 1, ActionMailer::Base.deliveries.size
1537 end
1552 end
1538
1553
1539 def test_stale_issue_should_not_send_email_notification
1554 def test_stale_issue_should_not_send_email_notification
1540 ActionMailer::Base.deliveries.clear
1555 ActionMailer::Base.deliveries.clear
1541 issue = Issue.find(1)
1556 issue = Issue.find(1)
1542 stale = Issue.find(1)
1557 stale = Issue.find(1)
1543
1558
1544 issue.init_journal(User.find(1))
1559 issue.init_journal(User.find(1))
1545 issue.subject = 'Subjet update'
1560 issue.subject = 'Subjet update'
1546 assert issue.save
1561 assert issue.save
1547 assert_equal 1, ActionMailer::Base.deliveries.size
1562 assert_equal 1, ActionMailer::Base.deliveries.size
1548 ActionMailer::Base.deliveries.clear
1563 ActionMailer::Base.deliveries.clear
1549
1564
1550 stale.init_journal(User.find(1))
1565 stale.init_journal(User.find(1))
1551 stale.subject = 'Another subjet update'
1566 stale.subject = 'Another subjet update'
1552 assert_raise ActiveRecord::StaleObjectError do
1567 assert_raise ActiveRecord::StaleObjectError do
1553 stale.save
1568 stale.save
1554 end
1569 end
1555 assert ActionMailer::Base.deliveries.empty?
1570 assert ActionMailer::Base.deliveries.empty?
1556 end
1571 end
1557
1572
1558 def test_journalized_description
1573 def test_journalized_description
1559 IssueCustomField.delete_all
1574 IssueCustomField.delete_all
1560
1575
1561 i = Issue.first
1576 i = Issue.first
1562 old_description = i.description
1577 old_description = i.description
1563 new_description = "This is the new description"
1578 new_description = "This is the new description"
1564
1579
1565 i.init_journal(User.find(2))
1580 i.init_journal(User.find(2))
1566 i.description = new_description
1581 i.description = new_description
1567 assert_difference 'Journal.count', 1 do
1582 assert_difference 'Journal.count', 1 do
1568 assert_difference 'JournalDetail.count', 1 do
1583 assert_difference 'JournalDetail.count', 1 do
1569 i.save!
1584 i.save!
1570 end
1585 end
1571 end
1586 end
1572
1587
1573 detail = JournalDetail.first(:order => 'id DESC')
1588 detail = JournalDetail.first(:order => 'id DESC')
1574 assert_equal i, detail.journal.journalized
1589 assert_equal i, detail.journal.journalized
1575 assert_equal 'attr', detail.property
1590 assert_equal 'attr', detail.property
1576 assert_equal 'description', detail.prop_key
1591 assert_equal 'description', detail.prop_key
1577 assert_equal old_description, detail.old_value
1592 assert_equal old_description, detail.old_value
1578 assert_equal new_description, detail.value
1593 assert_equal new_description, detail.value
1579 end
1594 end
1580
1595
1581 def test_blank_descriptions_should_not_be_journalized
1596 def test_blank_descriptions_should_not_be_journalized
1582 IssueCustomField.delete_all
1597 IssueCustomField.delete_all
1583 Issue.update_all("description = NULL", "id=1")
1598 Issue.update_all("description = NULL", "id=1")
1584
1599
1585 i = Issue.find(1)
1600 i = Issue.find(1)
1586 i.init_journal(User.find(2))
1601 i.init_journal(User.find(2))
1587 i.subject = "blank description"
1602 i.subject = "blank description"
1588 i.description = "\r\n"
1603 i.description = "\r\n"
1589
1604
1590 assert_difference 'Journal.count', 1 do
1605 assert_difference 'Journal.count', 1 do
1591 assert_difference 'JournalDetail.count', 1 do
1606 assert_difference 'JournalDetail.count', 1 do
1592 i.save!
1607 i.save!
1593 end
1608 end
1594 end
1609 end
1595 end
1610 end
1596
1611
1597 def test_journalized_multi_custom_field
1612 def test_journalized_multi_custom_field
1598 field = IssueCustomField.create!(:name => 'filter', :field_format => 'list',
1613 field = IssueCustomField.create!(:name => 'filter', :field_format => 'list',
1599 :is_filter => true, :is_for_all => true,
1614 :is_filter => true, :is_for_all => true,
1600 :tracker_ids => [1],
1615 :tracker_ids => [1],
1601 :possible_values => ['value1', 'value2', 'value3'],
1616 :possible_values => ['value1', 'value2', 'value3'],
1602 :multiple => true)
1617 :multiple => true)
1603
1618
1604 issue = Issue.create!(:project_id => 1, :tracker_id => 1,
1619 issue = Issue.create!(:project_id => 1, :tracker_id => 1,
1605 :subject => 'Test', :author_id => 1)
1620 :subject => 'Test', :author_id => 1)
1606
1621
1607 assert_difference 'Journal.count' do
1622 assert_difference 'Journal.count' do
1608 assert_difference 'JournalDetail.count' do
1623 assert_difference 'JournalDetail.count' do
1609 issue.init_journal(User.first)
1624 issue.init_journal(User.first)
1610 issue.custom_field_values = {field.id => ['value1']}
1625 issue.custom_field_values = {field.id => ['value1']}
1611 issue.save!
1626 issue.save!
1612 end
1627 end
1613 assert_difference 'JournalDetail.count' do
1628 assert_difference 'JournalDetail.count' do
1614 issue.init_journal(User.first)
1629 issue.init_journal(User.first)
1615 issue.custom_field_values = {field.id => ['value1', 'value2']}
1630 issue.custom_field_values = {field.id => ['value1', 'value2']}
1616 issue.save!
1631 issue.save!
1617 end
1632 end
1618 assert_difference 'JournalDetail.count', 2 do
1633 assert_difference 'JournalDetail.count', 2 do
1619 issue.init_journal(User.first)
1634 issue.init_journal(User.first)
1620 issue.custom_field_values = {field.id => ['value3', 'value2']}
1635 issue.custom_field_values = {field.id => ['value3', 'value2']}
1621 issue.save!
1636 issue.save!
1622 end
1637 end
1623 assert_difference 'JournalDetail.count', 2 do
1638 assert_difference 'JournalDetail.count', 2 do
1624 issue.init_journal(User.first)
1639 issue.init_journal(User.first)
1625 issue.custom_field_values = {field.id => nil}
1640 issue.custom_field_values = {field.id => nil}
1626 issue.save!
1641 issue.save!
1627 end
1642 end
1628 end
1643 end
1629 end
1644 end
1630
1645
1631 def test_description_eol_should_be_normalized
1646 def test_description_eol_should_be_normalized
1632 i = Issue.new(:description => "CR \r LF \n CRLF \r\n")
1647 i = Issue.new(:description => "CR \r LF \n CRLF \r\n")
1633 assert_equal "CR \r\n LF \r\n CRLF \r\n", i.description
1648 assert_equal "CR \r\n LF \r\n CRLF \r\n", i.description
1634 end
1649 end
1635
1650
1636 def test_saving_twice_should_not_duplicate_journal_details
1651 def test_saving_twice_should_not_duplicate_journal_details
1637 i = Issue.first
1652 i = Issue.first
1638 i.init_journal(User.find(2), 'Some notes')
1653 i.init_journal(User.find(2), 'Some notes')
1639 # initial changes
1654 # initial changes
1640 i.subject = 'New subject'
1655 i.subject = 'New subject'
1641 i.done_ratio = i.done_ratio + 10
1656 i.done_ratio = i.done_ratio + 10
1642 assert_difference 'Journal.count' do
1657 assert_difference 'Journal.count' do
1643 assert i.save
1658 assert i.save
1644 end
1659 end
1645 # 1 more change
1660 # 1 more change
1646 i.priority = IssuePriority.where("id <> ?", i.priority_id).first
1661 i.priority = IssuePriority.where("id <> ?", i.priority_id).first
1647 assert_no_difference 'Journal.count' do
1662 assert_no_difference 'Journal.count' do
1648 assert_difference 'JournalDetail.count', 1 do
1663 assert_difference 'JournalDetail.count', 1 do
1649 i.save
1664 i.save
1650 end
1665 end
1651 end
1666 end
1652 # no more change
1667 # no more change
1653 assert_no_difference 'Journal.count' do
1668 assert_no_difference 'Journal.count' do
1654 assert_no_difference 'JournalDetail.count' do
1669 assert_no_difference 'JournalDetail.count' do
1655 i.save
1670 i.save
1656 end
1671 end
1657 end
1672 end
1658 end
1673 end
1659
1674
1660 def test_all_dependent_issues
1675 def test_all_dependent_issues
1661 IssueRelation.delete_all
1676 IssueRelation.delete_all
1662 assert IssueRelation.create!(:issue_from => Issue.find(1),
1677 assert IssueRelation.create!(:issue_from => Issue.find(1),
1663 :issue_to => Issue.find(2),
1678 :issue_to => Issue.find(2),
1664 :relation_type => IssueRelation::TYPE_PRECEDES)
1679 :relation_type => IssueRelation::TYPE_PRECEDES)
1665 assert IssueRelation.create!(:issue_from => Issue.find(2),
1680 assert IssueRelation.create!(:issue_from => Issue.find(2),
1666 :issue_to => Issue.find(3),
1681 :issue_to => Issue.find(3),
1667 :relation_type => IssueRelation::TYPE_PRECEDES)
1682 :relation_type => IssueRelation::TYPE_PRECEDES)
1668 assert IssueRelation.create!(:issue_from => Issue.find(3),
1683 assert IssueRelation.create!(:issue_from => Issue.find(3),
1669 :issue_to => Issue.find(8),
1684 :issue_to => Issue.find(8),
1670 :relation_type => IssueRelation::TYPE_PRECEDES)
1685 :relation_type => IssueRelation::TYPE_PRECEDES)
1671
1686
1672 assert_equal [2, 3, 8], Issue.find(1).all_dependent_issues.collect(&:id).sort
1687 assert_equal [2, 3, 8], Issue.find(1).all_dependent_issues.collect(&:id).sort
1673 end
1688 end
1674
1689
1675 def test_all_dependent_issues_with_persistent_circular_dependency
1690 def test_all_dependent_issues_with_persistent_circular_dependency
1676 IssueRelation.delete_all
1691 IssueRelation.delete_all
1677 assert IssueRelation.create!(:issue_from => Issue.find(1),
1692 assert IssueRelation.create!(:issue_from => Issue.find(1),
1678 :issue_to => Issue.find(2),
1693 :issue_to => Issue.find(2),
1679 :relation_type => IssueRelation::TYPE_PRECEDES)
1694 :relation_type => IssueRelation::TYPE_PRECEDES)
1680 assert IssueRelation.create!(:issue_from => Issue.find(2),
1695 assert IssueRelation.create!(:issue_from => Issue.find(2),
1681 :issue_to => Issue.find(3),
1696 :issue_to => Issue.find(3),
1682 :relation_type => IssueRelation::TYPE_PRECEDES)
1697 :relation_type => IssueRelation::TYPE_PRECEDES)
1683
1698
1684 r = IssueRelation.create!(:issue_from => Issue.find(3),
1699 r = IssueRelation.create!(:issue_from => Issue.find(3),
1685 :issue_to => Issue.find(7),
1700 :issue_to => Issue.find(7),
1686 :relation_type => IssueRelation::TYPE_PRECEDES)
1701 :relation_type => IssueRelation::TYPE_PRECEDES)
1687 IssueRelation.update_all("issue_to_id = 1", ["id = ?", r.id])
1702 IssueRelation.update_all("issue_to_id = 1", ["id = ?", r.id])
1688
1703
1689 assert_equal [2, 3], Issue.find(1).all_dependent_issues.collect(&:id).sort
1704 assert_equal [2, 3], Issue.find(1).all_dependent_issues.collect(&:id).sort
1690 end
1705 end
1691
1706
1692 def test_all_dependent_issues_with_persistent_multiple_circular_dependencies
1707 def test_all_dependent_issues_with_persistent_multiple_circular_dependencies
1693 IssueRelation.delete_all
1708 IssueRelation.delete_all
1694 assert IssueRelation.create!(:issue_from => Issue.find(1),
1709 assert IssueRelation.create!(:issue_from => Issue.find(1),
1695 :issue_to => Issue.find(2),
1710 :issue_to => Issue.find(2),
1696 :relation_type => IssueRelation::TYPE_RELATES)
1711 :relation_type => IssueRelation::TYPE_RELATES)
1697 assert IssueRelation.create!(:issue_from => Issue.find(2),
1712 assert IssueRelation.create!(:issue_from => Issue.find(2),
1698 :issue_to => Issue.find(3),
1713 :issue_to => Issue.find(3),
1699 :relation_type => IssueRelation::TYPE_RELATES)
1714 :relation_type => IssueRelation::TYPE_RELATES)
1700 assert IssueRelation.create!(:issue_from => Issue.find(3),
1715 assert IssueRelation.create!(:issue_from => Issue.find(3),
1701 :issue_to => Issue.find(8),
1716 :issue_to => Issue.find(8),
1702 :relation_type => IssueRelation::TYPE_RELATES)
1717 :relation_type => IssueRelation::TYPE_RELATES)
1703
1718
1704 r = IssueRelation.create!(:issue_from => Issue.find(8),
1719 r = IssueRelation.create!(:issue_from => Issue.find(8),
1705 :issue_to => Issue.find(7),
1720 :issue_to => Issue.find(7),
1706 :relation_type => IssueRelation::TYPE_RELATES)
1721 :relation_type => IssueRelation::TYPE_RELATES)
1707 IssueRelation.update_all("issue_to_id = 2", ["id = ?", r.id])
1722 IssueRelation.update_all("issue_to_id = 2", ["id = ?", r.id])
1708
1723
1709 r = IssueRelation.create!(:issue_from => Issue.find(3),
1724 r = IssueRelation.create!(:issue_from => Issue.find(3),
1710 :issue_to => Issue.find(7),
1725 :issue_to => Issue.find(7),
1711 :relation_type => IssueRelation::TYPE_RELATES)
1726 :relation_type => IssueRelation::TYPE_RELATES)
1712 IssueRelation.update_all("issue_to_id = 1", ["id = ?", r.id])
1727 IssueRelation.update_all("issue_to_id = 1", ["id = ?", r.id])
1713
1728
1714 assert_equal [2, 3, 8], Issue.find(1).all_dependent_issues.collect(&:id).sort
1729 assert_equal [2, 3, 8], Issue.find(1).all_dependent_issues.collect(&:id).sort
1715 end
1730 end
1716
1731
1717 test "#done_ratio should use the issue_status according to Setting.issue_done_ratio" do
1732 test "#done_ratio should use the issue_status according to Setting.issue_done_ratio" do
1718 @issue = Issue.find(1)
1733 @issue = Issue.find(1)
1719 @issue_status = IssueStatus.find(1)
1734 @issue_status = IssueStatus.find(1)
1720 @issue_status.update_attribute(:default_done_ratio, 50)
1735 @issue_status.update_attribute(:default_done_ratio, 50)
1721 @issue2 = Issue.find(2)
1736 @issue2 = Issue.find(2)
1722 @issue_status2 = IssueStatus.find(2)
1737 @issue_status2 = IssueStatus.find(2)
1723 @issue_status2.update_attribute(:default_done_ratio, 0)
1738 @issue_status2.update_attribute(:default_done_ratio, 0)
1724
1739
1725 with_settings :issue_done_ratio => 'issue_field' do
1740 with_settings :issue_done_ratio => 'issue_field' do
1726 assert_equal 0, @issue.done_ratio
1741 assert_equal 0, @issue.done_ratio
1727 assert_equal 30, @issue2.done_ratio
1742 assert_equal 30, @issue2.done_ratio
1728 end
1743 end
1729
1744
1730 with_settings :issue_done_ratio => 'issue_status' do
1745 with_settings :issue_done_ratio => 'issue_status' do
1731 assert_equal 50, @issue.done_ratio
1746 assert_equal 50, @issue.done_ratio
1732 assert_equal 0, @issue2.done_ratio
1747 assert_equal 0, @issue2.done_ratio
1733 end
1748 end
1734 end
1749 end
1735
1750
1736 test "#update_done_ratio_from_issue_status should update done_ratio according to Setting.issue_done_ratio" do
1751 test "#update_done_ratio_from_issue_status should update done_ratio according to Setting.issue_done_ratio" do
1737 @issue = Issue.find(1)
1752 @issue = Issue.find(1)
1738 @issue_status = IssueStatus.find(1)
1753 @issue_status = IssueStatus.find(1)
1739 @issue_status.update_attribute(:default_done_ratio, 50)
1754 @issue_status.update_attribute(:default_done_ratio, 50)
1740 @issue2 = Issue.find(2)
1755 @issue2 = Issue.find(2)
1741 @issue_status2 = IssueStatus.find(2)
1756 @issue_status2 = IssueStatus.find(2)
1742 @issue_status2.update_attribute(:default_done_ratio, 0)
1757 @issue_status2.update_attribute(:default_done_ratio, 0)
1743
1758
1744 with_settings :issue_done_ratio => 'issue_field' do
1759 with_settings :issue_done_ratio => 'issue_field' do
1745 @issue.update_done_ratio_from_issue_status
1760 @issue.update_done_ratio_from_issue_status
1746 @issue2.update_done_ratio_from_issue_status
1761 @issue2.update_done_ratio_from_issue_status
1747
1762
1748 assert_equal 0, @issue.read_attribute(:done_ratio)
1763 assert_equal 0, @issue.read_attribute(:done_ratio)
1749 assert_equal 30, @issue2.read_attribute(:done_ratio)
1764 assert_equal 30, @issue2.read_attribute(:done_ratio)
1750 end
1765 end
1751
1766
1752 with_settings :issue_done_ratio => 'issue_status' do
1767 with_settings :issue_done_ratio => 'issue_status' do
1753 @issue.update_done_ratio_from_issue_status
1768 @issue.update_done_ratio_from_issue_status
1754 @issue2.update_done_ratio_from_issue_status
1769 @issue2.update_done_ratio_from_issue_status
1755
1770
1756 assert_equal 50, @issue.read_attribute(:done_ratio)
1771 assert_equal 50, @issue.read_attribute(:done_ratio)
1757 assert_equal 0, @issue2.read_attribute(:done_ratio)
1772 assert_equal 0, @issue2.read_attribute(:done_ratio)
1758 end
1773 end
1759 end
1774 end
1760
1775
1761 test "#by_tracker" do
1776 test "#by_tracker" do
1762 User.current = User.anonymous
1777 User.current = User.anonymous
1763 groups = Issue.by_tracker(Project.find(1))
1778 groups = Issue.by_tracker(Project.find(1))
1764 assert_equal 3, groups.size
1779 assert_equal 3, groups.size
1765 assert_equal 7, groups.inject(0) {|sum, group| sum + group['total'].to_i}
1780 assert_equal 7, groups.inject(0) {|sum, group| sum + group['total'].to_i}
1766 end
1781 end
1767
1782
1768 test "#by_version" do
1783 test "#by_version" do
1769 User.current = User.anonymous
1784 User.current = User.anonymous
1770 groups = Issue.by_version(Project.find(1))
1785 groups = Issue.by_version(Project.find(1))
1771 assert_equal 3, groups.size
1786 assert_equal 3, groups.size
1772 assert_equal 3, groups.inject(0) {|sum, group| sum + group['total'].to_i}
1787 assert_equal 3, groups.inject(0) {|sum, group| sum + group['total'].to_i}
1773 end
1788 end
1774
1789
1775 test "#by_priority" do
1790 test "#by_priority" do
1776 User.current = User.anonymous
1791 User.current = User.anonymous
1777 groups = Issue.by_priority(Project.find(1))
1792 groups = Issue.by_priority(Project.find(1))
1778 assert_equal 4, groups.size
1793 assert_equal 4, groups.size
1779 assert_equal 7, groups.inject(0) {|sum, group| sum + group['total'].to_i}
1794 assert_equal 7, groups.inject(0) {|sum, group| sum + group['total'].to_i}
1780 end
1795 end
1781
1796
1782 test "#by_category" do
1797 test "#by_category" do
1783 User.current = User.anonymous
1798 User.current = User.anonymous
1784 groups = Issue.by_category(Project.find(1))
1799 groups = Issue.by_category(Project.find(1))
1785 assert_equal 2, groups.size
1800 assert_equal 2, groups.size
1786 assert_equal 3, groups.inject(0) {|sum, group| sum + group['total'].to_i}
1801 assert_equal 3, groups.inject(0) {|sum, group| sum + group['total'].to_i}
1787 end
1802 end
1788
1803
1789 test "#by_assigned_to" do
1804 test "#by_assigned_to" do
1790 User.current = User.anonymous
1805 User.current = User.anonymous
1791 groups = Issue.by_assigned_to(Project.find(1))
1806 groups = Issue.by_assigned_to(Project.find(1))
1792 assert_equal 2, groups.size
1807 assert_equal 2, groups.size
1793 assert_equal 2, groups.inject(0) {|sum, group| sum + group['total'].to_i}
1808 assert_equal 2, groups.inject(0) {|sum, group| sum + group['total'].to_i}
1794 end
1809 end
1795
1810
1796 test "#by_author" do
1811 test "#by_author" do
1797 User.current = User.anonymous
1812 User.current = User.anonymous
1798 groups = Issue.by_author(Project.find(1))
1813 groups = Issue.by_author(Project.find(1))
1799 assert_equal 4, groups.size
1814 assert_equal 4, groups.size
1800 assert_equal 7, groups.inject(0) {|sum, group| sum + group['total'].to_i}
1815 assert_equal 7, groups.inject(0) {|sum, group| sum + group['total'].to_i}
1801 end
1816 end
1802
1817
1803 test "#by_subproject" do
1818 test "#by_subproject" do
1804 User.current = User.anonymous
1819 User.current = User.anonymous
1805 groups = Issue.by_subproject(Project.find(1))
1820 groups = Issue.by_subproject(Project.find(1))
1806 # Private descendant not visible
1821 # Private descendant not visible
1807 assert_equal 1, groups.size
1822 assert_equal 1, groups.size
1808 assert_equal 2, groups.inject(0) {|sum, group| sum + group['total'].to_i}
1823 assert_equal 2, groups.inject(0) {|sum, group| sum + group['total'].to_i}
1809 end
1824 end
1810
1825
1811 def test_recently_updated_scope
1826 def test_recently_updated_scope
1812 #should return the last updated issue
1827 #should return the last updated issue
1813 assert_equal Issue.reorder("updated_on DESC").first, Issue.recently_updated.limit(1).first
1828 assert_equal Issue.reorder("updated_on DESC").first, Issue.recently_updated.limit(1).first
1814 end
1829 end
1815
1830
1816 def test_on_active_projects_scope
1831 def test_on_active_projects_scope
1817 assert Project.find(2).archive
1832 assert Project.find(2).archive
1818
1833
1819 before = Issue.on_active_project.length
1834 before = Issue.on_active_project.length
1820 # test inclusion to results
1835 # test inclusion to results
1821 issue = Issue.generate!(:tracker => Project.find(2).trackers.first)
1836 issue = Issue.generate!(:tracker => Project.find(2).trackers.first)
1822 assert_equal before + 1, Issue.on_active_project.length
1837 assert_equal before + 1, Issue.on_active_project.length
1823
1838
1824 # Move to an archived project
1839 # Move to an archived project
1825 issue.project = Project.find(2)
1840 issue.project = Project.find(2)
1826 assert issue.save
1841 assert issue.save
1827 assert_equal before, Issue.on_active_project.length
1842 assert_equal before, Issue.on_active_project.length
1828 end
1843 end
1829
1844
1830 test "Issue#recipients should include project recipients" do
1845 test "Issue#recipients should include project recipients" do
1831 issue = Issue.generate!
1846 issue = Issue.generate!
1832 assert issue.project.recipients.present?
1847 assert issue.project.recipients.present?
1833 issue.project.recipients.each do |project_recipient|
1848 issue.project.recipients.each do |project_recipient|
1834 assert issue.recipients.include?(project_recipient)
1849 assert issue.recipients.include?(project_recipient)
1835 end
1850 end
1836 end
1851 end
1837
1852
1838 test "Issue#recipients should include the author if the author is active" do
1853 test "Issue#recipients should include the author if the author is active" do
1839 issue = Issue.generate!(:author => User.generate!)
1854 issue = Issue.generate!(:author => User.generate!)
1840 assert issue.author, "No author set for Issue"
1855 assert issue.author, "No author set for Issue"
1841 assert issue.recipients.include?(issue.author.mail)
1856 assert issue.recipients.include?(issue.author.mail)
1842 end
1857 end
1843
1858
1844 test "Issue#recipients should include the assigned to user if the assigned to user is active" do
1859 test "Issue#recipients should include the assigned to user if the assigned to user is active" do
1845 issue = Issue.generate!(:assigned_to => User.generate!)
1860 issue = Issue.generate!(:assigned_to => User.generate!)
1846 assert issue.assigned_to, "No assigned_to set for Issue"
1861 assert issue.assigned_to, "No assigned_to set for Issue"
1847 assert issue.recipients.include?(issue.assigned_to.mail)
1862 assert issue.recipients.include?(issue.assigned_to.mail)
1848 end
1863 end
1849
1864
1850 test "Issue#recipients should not include users who opt out of all email" do
1865 test "Issue#recipients should not include users who opt out of all email" do
1851 issue = Issue.generate!(:author => User.generate!)
1866 issue = Issue.generate!(:author => User.generate!)
1852 issue.author.update_attribute(:mail_notification, :none)
1867 issue.author.update_attribute(:mail_notification, :none)
1853 assert !issue.recipients.include?(issue.author.mail)
1868 assert !issue.recipients.include?(issue.author.mail)
1854 end
1869 end
1855
1870
1856 test "Issue#recipients should not include the issue author if they are only notified of assigned issues" do
1871 test "Issue#recipients should not include the issue author if they are only notified of assigned issues" do
1857 issue = Issue.generate!(:author => User.generate!)
1872 issue = Issue.generate!(:author => User.generate!)
1858 issue.author.update_attribute(:mail_notification, :only_assigned)
1873 issue.author.update_attribute(:mail_notification, :only_assigned)
1859 assert !issue.recipients.include?(issue.author.mail)
1874 assert !issue.recipients.include?(issue.author.mail)
1860 end
1875 end
1861
1876
1862 test "Issue#recipients should not include the assigned user if they are only notified of owned issues" do
1877 test "Issue#recipients should not include the assigned user if they are only notified of owned issues" do
1863 issue = Issue.generate!(:assigned_to => User.generate!)
1878 issue = Issue.generate!(:assigned_to => User.generate!)
1864 issue.assigned_to.update_attribute(:mail_notification, :only_owner)
1879 issue.assigned_to.update_attribute(:mail_notification, :only_owner)
1865 assert !issue.recipients.include?(issue.assigned_to.mail)
1880 assert !issue.recipients.include?(issue.assigned_to.mail)
1866 end
1881 end
1867
1882
1868 def test_last_journal_id_with_journals_should_return_the_journal_id
1883 def test_last_journal_id_with_journals_should_return_the_journal_id
1869 assert_equal 2, Issue.find(1).last_journal_id
1884 assert_equal 2, Issue.find(1).last_journal_id
1870 end
1885 end
1871
1886
1872 def test_last_journal_id_without_journals_should_return_nil
1887 def test_last_journal_id_without_journals_should_return_nil
1873 assert_nil Issue.find(3).last_journal_id
1888 assert_nil Issue.find(3).last_journal_id
1874 end
1889 end
1875
1890
1876 def test_journals_after_should_return_journals_with_greater_id
1891 def test_journals_after_should_return_journals_with_greater_id
1877 assert_equal [Journal.find(2)], Issue.find(1).journals_after('1')
1892 assert_equal [Journal.find(2)], Issue.find(1).journals_after('1')
1878 assert_equal [], Issue.find(1).journals_after('2')
1893 assert_equal [], Issue.find(1).journals_after('2')
1879 end
1894 end
1880
1895
1881 def test_journals_after_with_blank_arg_should_return_all_journals
1896 def test_journals_after_with_blank_arg_should_return_all_journals
1882 assert_equal [Journal.find(1), Journal.find(2)], Issue.find(1).journals_after('')
1897 assert_equal [Journal.find(1), Journal.find(2)], Issue.find(1).journals_after('')
1883 end
1898 end
1884
1899
1885 def test_css_classes_should_include_priority
1900 def test_css_classes_should_include_priority
1886 issue = Issue.new(:priority => IssuePriority.find(8))
1901 issue = Issue.new(:priority => IssuePriority.find(8))
1887 classes = issue.css_classes.split(' ')
1902 classes = issue.css_classes.split(' ')
1888 assert_include 'priority-8', classes
1903 assert_include 'priority-8', classes
1889 assert_include 'priority-highest', classes
1904 assert_include 'priority-highest', classes
1890 end
1905 end
1891
1906
1892 def test_save_attachments_with_hash_should_save_attachments_in_keys_order
1907 def test_save_attachments_with_hash_should_save_attachments_in_keys_order
1893 set_tmp_attachments_directory
1908 set_tmp_attachments_directory
1894 issue = Issue.generate!
1909 issue = Issue.generate!
1895 issue.save_attachments({
1910 issue.save_attachments({
1896 'p0' => {'file' => mock_file_with_options(:original_filename => 'upload')},
1911 'p0' => {'file' => mock_file_with_options(:original_filename => 'upload')},
1897 '3' => {'file' => mock_file_with_options(:original_filename => 'bar')},
1912 '3' => {'file' => mock_file_with_options(:original_filename => 'bar')},
1898 '1' => {'file' => mock_file_with_options(:original_filename => 'foo')}
1913 '1' => {'file' => mock_file_with_options(:original_filename => 'foo')}
1899 })
1914 })
1900 issue.attach_saved_attachments
1915 issue.attach_saved_attachments
1901
1916
1902 assert_equal 3, issue.reload.attachments.count
1917 assert_equal 3, issue.reload.attachments.count
1903 assert_equal %w(upload foo bar), issue.attachments.map(&:filename)
1918 assert_equal %w(upload foo bar), issue.attachments.map(&:filename)
1904 end
1919 end
1905 end
1920 end
General Comments 0
You need to be logged in to leave comments. Login now