You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

issue_test.rb 84KB

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