@@ -1,42 +1,43 | |||
|
1 | 1 | # Redmine - project management software |
|
2 | 2 | # Copyright (C) 2006-2016 Jean-Philippe Lang |
|
3 | 3 | # |
|
4 | 4 | # This program is free software; you can redistribute it and/or |
|
5 | 5 | # modify it under the terms of the GNU General Public License |
|
6 | 6 | # as published by the Free Software Foundation; either version 2 |
|
7 | 7 | # of the License, or (at your option) any later version. |
|
8 | 8 | # |
|
9 | 9 | # This program is distributed in the hope that it will be useful, |
|
10 | 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 | 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 | 12 | # GNU General Public License for more details. |
|
13 | 13 | # |
|
14 | 14 | # You should have received a copy of the GNU General Public License |
|
15 | 15 | # along with this program; if not, write to the Free Software |
|
16 | 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
17 | 17 | |
|
18 | 18 | require File.expand_path('../../../test_helper', __FILE__) |
|
19 | 19 | |
|
20 | 20 | class GroupsHelperTest < Redmine::HelperTest |
|
21 | 21 | include Redmine::I18n |
|
22 | 22 | include ERB::Util |
|
23 | 23 | include GroupsHelper |
|
24 | include Rails.application.routes.url_helpers | |
|
24 | 25 | |
|
25 | 26 | fixtures :users |
|
26 | 27 | |
|
27 | 28 | def test_render_principals_for_new_group_users |
|
28 | 29 | group = Group.generate! |
|
29 | 30 | |
|
30 | 31 | result = render_principals_for_new_group_users(group) |
|
31 | 32 | assert_select_in result, 'input[name=?][value="2"]', 'user_ids[]' |
|
32 | 33 | end |
|
33 | 34 | |
|
34 | 35 | def test_render_principals_for_new_group_users_with_limited_results_should_paginate |
|
35 | 36 | group = Group.generate! |
|
36 | 37 | |
|
37 | 38 | result = render_principals_for_new_group_users(group, 3) |
|
38 | 39 | assert_select_in result, 'span.pagination' |
|
39 | 40 | assert_select_in result, 'span.pagination li.current span', :text => '1' |
|
40 | 41 | assert_select_in result, 'a[href=?]', "/groups/#{group.id}/autocomplete_for_user.js?page=2", :text => '2' |
|
41 | 42 | end |
|
42 | 43 | end |
@@ -1,339 +1,339 | |||
|
1 | 1 | # Redmine - project management software |
|
2 | 2 | # Copyright (C) 2006-2016 Jean-Philippe Lang |
|
3 | 3 | # |
|
4 | 4 | # This program is free software; you can redistribute it and/or |
|
5 | 5 | # modify it under the terms of the GNU General Public License |
|
6 | 6 | # as published by the Free Software Foundation; either version 2 |
|
7 | 7 | # of the License, or (at your option) any later version. |
|
8 | 8 | # |
|
9 | 9 | # This program is distributed in the hope that it will be useful, |
|
10 | 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 | 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 | 12 | # GNU General Public License for more details. |
|
13 | 13 | # |
|
14 | 14 | # You should have received a copy of the GNU General Public License |
|
15 | 15 | # along with this program; if not, write to the Free Software |
|
16 | 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
17 | 17 | |
|
18 | 18 | require File.expand_path('../../../test_helper', __FILE__) |
|
19 | 19 | |
|
20 | 20 | class IssuesHelperTest < Redmine::HelperTest |
|
21 | 21 | include Redmine::I18n |
|
22 | 22 | include IssuesHelper |
|
23 | 23 | include CustomFieldsHelper |
|
24 | 24 | include ERB::Util |
|
25 | 25 | include Rails.application.routes.url_helpers |
|
26 | 26 | |
|
27 | 27 | fixtures :projects, :trackers, :issue_statuses, :issues, |
|
28 | 28 | :enumerations, :users, :issue_categories, |
|
29 | 29 | :projects_trackers, |
|
30 | 30 | :roles, |
|
31 | 31 | :member_roles, |
|
32 | 32 | :members, |
|
33 | 33 | :enabled_modules, |
|
34 | 34 | :custom_fields, |
|
35 | 35 | :attachments, |
|
36 | 36 | :versions |
|
37 | 37 | |
|
38 | 38 | def setup |
|
39 | 39 | super |
|
40 | 40 | set_language_if_valid('en') |
|
41 | 41 | User.current = nil |
|
42 | 42 | end |
|
43 | 43 | |
|
44 | 44 | def test_issue_heading |
|
45 | 45 | assert_equal "Bug #1", issue_heading(Issue.find(1)) |
|
46 | 46 | end |
|
47 | 47 | |
|
48 | 48 | def test_issues_destroy_confirmation_message_with_one_root_issue |
|
49 | 49 | assert_equal l(:text_issues_destroy_confirmation), |
|
50 | 50 | issues_destroy_confirmation_message(Issue.find(1)) |
|
51 | 51 | end |
|
52 | 52 | |
|
53 | 53 | def test_issues_destroy_confirmation_message_with_an_arrayt_of_root_issues |
|
54 | 54 | assert_equal l(:text_issues_destroy_confirmation), |
|
55 | 55 | issues_destroy_confirmation_message(Issue.find([1, 2])) |
|
56 | 56 | end |
|
57 | 57 | |
|
58 | 58 | def test_issues_destroy_confirmation_message_with_one_parent_issue |
|
59 |
Issue.find(2).update |
|
|
59 | Issue.find(2).update! :parent_issue_id => 1 | |
|
60 | 60 | assert_equal l(:text_issues_destroy_confirmation) + "\n" + |
|
61 | 61 | l(:text_issues_destroy_descendants_confirmation, :count => 1), |
|
62 | 62 | issues_destroy_confirmation_message(Issue.find(1)) |
|
63 | 63 | end |
|
64 | 64 | |
|
65 | 65 | def test_issues_destroy_confirmation_message_with_one_parent_issue_and_its_child |
|
66 |
Issue.find(2).update |
|
|
66 | Issue.find(2).update! :parent_issue_id => 1 | |
|
67 | 67 | assert_equal l(:text_issues_destroy_confirmation), |
|
68 | 68 | issues_destroy_confirmation_message(Issue.find([1, 2])) |
|
69 | 69 | end |
|
70 | 70 | |
|
71 | 71 | def test_issues_destroy_confirmation_message_with_issues_that_share_descendants |
|
72 | 72 | root = Issue.generate! |
|
73 | 73 | child = Issue.generate!(:parent_issue_id => root.id) |
|
74 | 74 | Issue.generate!(:parent_issue_id => child.id) |
|
75 | 75 | |
|
76 | 76 | assert_equal l(:text_issues_destroy_confirmation) + "\n" + |
|
77 | 77 | l(:text_issues_destroy_descendants_confirmation, :count => 1), |
|
78 | 78 | issues_destroy_confirmation_message([root.reload, child.reload]) |
|
79 | 79 | end |
|
80 | 80 | |
|
81 | 81 | test 'show_detail with no_html should show a changing attribute' do |
|
82 | 82 | detail = JournalDetail.new(:property => 'attr', :old_value => '40', |
|
83 | 83 | :value => '100', :prop_key => 'done_ratio') |
|
84 | 84 | assert_equal "% Done changed from 40 to 100", show_detail(detail, true) |
|
85 | 85 | end |
|
86 | 86 | |
|
87 | 87 | test 'show_detail with no_html should show a new attribute' do |
|
88 | 88 | detail = JournalDetail.new(:property => 'attr', :old_value => nil, |
|
89 | 89 | :value => '100', :prop_key => 'done_ratio') |
|
90 | 90 | assert_equal "% Done set to 100", show_detail(detail, true) |
|
91 | 91 | end |
|
92 | 92 | |
|
93 | 93 | test 'show_detail with no_html should show a deleted attribute' do |
|
94 | 94 | detail = JournalDetail.new(:property => 'attr', :old_value => '50', |
|
95 | 95 | :value => nil, :prop_key => 'done_ratio') |
|
96 | 96 | assert_equal "% Done deleted (50)", show_detail(detail, true) |
|
97 | 97 | end |
|
98 | 98 | |
|
99 | 99 | test 'show_detail with html should show a changing attribute with HTML highlights' do |
|
100 | 100 | detail = JournalDetail.new(:property => 'attr', :old_value => '40', |
|
101 | 101 | :value => '100', :prop_key => 'done_ratio') |
|
102 | 102 | html = show_detail(detail, false) |
|
103 | 103 | assert_include '<strong>% Done</strong>', html |
|
104 | 104 | assert_include '<i>40</i>', html |
|
105 | 105 | assert_include '<i>100</i>', html |
|
106 | 106 | end |
|
107 | 107 | |
|
108 | 108 | test 'show_detail with html should show a new attribute with HTML highlights' do |
|
109 | 109 | detail = JournalDetail.new(:property => 'attr', :old_value => nil, |
|
110 | 110 | :value => '100', :prop_key => 'done_ratio') |
|
111 | 111 | html = show_detail(detail, false) |
|
112 | 112 | assert_include '<strong>% Done</strong>', html |
|
113 | 113 | assert_include '<i>100</i>', html |
|
114 | 114 | end |
|
115 | 115 | |
|
116 | 116 | test 'show_detail with html should show a deleted attribute with HTML highlights' do |
|
117 | 117 | detail = JournalDetail.new(:property => 'attr', :old_value => '50', |
|
118 | 118 | :value => nil, :prop_key => 'done_ratio') |
|
119 | 119 | html = show_detail(detail, false) |
|
120 | 120 | assert_include '<strong>% Done</strong>', html |
|
121 | 121 | assert_include '<del><i>50</i></del>', html |
|
122 | 122 | end |
|
123 | 123 | |
|
124 | 124 | test 'show_detail with a start_date attribute should format the dates' do |
|
125 | 125 | detail = JournalDetail.new( |
|
126 | 126 | :property => 'attr', |
|
127 | 127 | :old_value => '2010-01-01', |
|
128 | 128 | :value => '2010-01-31', |
|
129 | 129 | :prop_key => 'start_date' |
|
130 | 130 | ) |
|
131 | 131 | with_settings :date_format => '%m/%d/%Y' do |
|
132 | 132 | assert_match "01/31/2010", show_detail(detail, true) |
|
133 | 133 | assert_match "01/01/2010", show_detail(detail, true) |
|
134 | 134 | end |
|
135 | 135 | end |
|
136 | 136 | |
|
137 | 137 | test 'show_detail with a due_date attribute should format the dates' do |
|
138 | 138 | detail = JournalDetail.new( |
|
139 | 139 | :property => 'attr', |
|
140 | 140 | :old_value => '2010-01-01', |
|
141 | 141 | :value => '2010-01-31', |
|
142 | 142 | :prop_key => 'due_date' |
|
143 | 143 | ) |
|
144 | 144 | with_settings :date_format => '%m/%d/%Y' do |
|
145 | 145 | assert_match "01/31/2010", show_detail(detail, true) |
|
146 | 146 | assert_match "01/01/2010", show_detail(detail, true) |
|
147 | 147 | end |
|
148 | 148 | end |
|
149 | 149 | |
|
150 | 150 | test 'show_detail should show old and new values with a project attribute' do |
|
151 | 151 | detail = JournalDetail.new(:property => 'attr', :prop_key => 'project_id', |
|
152 | 152 | :old_value => 1, :value => 2) |
|
153 | 153 | assert_match 'eCookbook', show_detail(detail, true) |
|
154 | 154 | assert_match 'OnlineStore', show_detail(detail, true) |
|
155 | 155 | end |
|
156 | 156 | |
|
157 | 157 | test 'show_detail should show old and new values with a issue status attribute' do |
|
158 | 158 | detail = JournalDetail.new(:property => 'attr', :prop_key => 'status_id', |
|
159 | 159 | :old_value => 1, :value => 2) |
|
160 | 160 | assert_match 'New', show_detail(detail, true) |
|
161 | 161 | assert_match 'Assigned', show_detail(detail, true) |
|
162 | 162 | end |
|
163 | 163 | |
|
164 | 164 | test 'show_detail should show old and new values with a tracker attribute' do |
|
165 | 165 | detail = JournalDetail.new(:property => 'attr', :prop_key => 'tracker_id', |
|
166 | 166 | :old_value => 1, :value => 2) |
|
167 | 167 | assert_match 'Bug', show_detail(detail, true) |
|
168 | 168 | assert_match 'Feature request', show_detail(detail, true) |
|
169 | 169 | end |
|
170 | 170 | |
|
171 | 171 | test 'show_detail should show old and new values with a assigned to attribute' do |
|
172 | 172 | detail = JournalDetail.new(:property => 'attr', :prop_key => 'assigned_to_id', |
|
173 | 173 | :old_value => 1, :value => 2) |
|
174 | 174 | assert_match 'Redmine Admin', show_detail(detail, true) |
|
175 | 175 | assert_match 'John Smith', show_detail(detail, true) |
|
176 | 176 | end |
|
177 | 177 | |
|
178 | 178 | test 'show_detail should show old and new values with a priority attribute' do |
|
179 | 179 | detail = JournalDetail.new(:property => 'attr', :prop_key => 'priority_id', |
|
180 | 180 | :old_value => 4, :value => 5) |
|
181 | 181 | assert_match 'Low', show_detail(detail, true) |
|
182 | 182 | assert_match 'Normal', show_detail(detail, true) |
|
183 | 183 | end |
|
184 | 184 | |
|
185 | 185 | test 'show_detail should show old and new values with a category attribute' do |
|
186 | 186 | detail = JournalDetail.new(:property => 'attr', :prop_key => 'category_id', |
|
187 | 187 | :old_value => 1, :value => 2) |
|
188 | 188 | assert_match 'Printing', show_detail(detail, true) |
|
189 | 189 | assert_match 'Recipes', show_detail(detail, true) |
|
190 | 190 | end |
|
191 | 191 | |
|
192 | 192 | test 'show_detail should show old and new values with a fixed version attribute' do |
|
193 | 193 | detail = JournalDetail.new(:property => 'attr', :prop_key => 'fixed_version_id', |
|
194 | 194 | :old_value => 1, :value => 2) |
|
195 | 195 | assert_match '0.1', show_detail(detail, true) |
|
196 | 196 | assert_match '1.0', show_detail(detail, true) |
|
197 | 197 | end |
|
198 | 198 | |
|
199 | 199 | test 'show_detail should show old and new values with a estimated hours attribute' do |
|
200 | 200 | detail = JournalDetail.new(:property => 'attr', :prop_key => 'estimated_hours', |
|
201 | 201 | :old_value => '5', :value => '6.3') |
|
202 | 202 | assert_match '5.00', show_detail(detail, true) |
|
203 | 203 | assert_match '6.30', show_detail(detail, true) |
|
204 | 204 | end |
|
205 | 205 | |
|
206 | 206 | test 'show_detail should not show values with a description attribute' do |
|
207 | 207 | detail = JournalDetail.new(:property => 'attr', :prop_key => 'description', |
|
208 | 208 | :old_value => 'Foo', :value => 'Bar') |
|
209 | 209 | assert_equal 'Description updated', show_detail(detail, true) |
|
210 | 210 | end |
|
211 | 211 | |
|
212 | 212 | test 'show_detail should show old and new values with a custom field' do |
|
213 | 213 | detail = JournalDetail.new(:property => 'cf', :prop_key => '1', |
|
214 | 214 | :old_value => 'MySQL', :value => 'PostgreSQL') |
|
215 | 215 | assert_equal 'Database changed from MySQL to PostgreSQL', show_detail(detail, true) |
|
216 | 216 | end |
|
217 | 217 | |
|
218 | 218 | test 'show_detail should not show values with a long text custom field' do |
|
219 | 219 | field = IssueCustomField.create!(:name => "Long field", :field_format => 'text') |
|
220 | 220 | detail = JournalDetail.new(:property => 'cf', :prop_key => field.id, |
|
221 | 221 | :old_value => 'Foo', :value => 'Bar') |
|
222 | 222 | assert_equal 'Long field updated', show_detail(detail, true) |
|
223 | 223 | end |
|
224 | 224 | |
|
225 | 225 | test 'show_detail should show added file' do |
|
226 | 226 | detail = JournalDetail.new(:property => 'attachment', :prop_key => '1', |
|
227 | 227 | :old_value => nil, :value => 'error281.txt') |
|
228 | 228 | assert_match 'error281.txt', show_detail(detail, true) |
|
229 | 229 | end |
|
230 | 230 | |
|
231 | 231 | test 'show_detail should show removed file' do |
|
232 | 232 | detail = JournalDetail.new(:property => 'attachment', :prop_key => '1', |
|
233 | 233 | :old_value => 'error281.txt', :value => nil) |
|
234 | 234 | assert_match 'error281.txt', show_detail(detail, true) |
|
235 | 235 | end |
|
236 | 236 | |
|
237 | 237 | def test_show_detail_relation_added |
|
238 | 238 | detail = JournalDetail.new(:property => 'relation', |
|
239 | 239 | :prop_key => 'precedes', |
|
240 | 240 | :value => 1) |
|
241 | 241 | assert_equal "Precedes Bug #1: Cannot print recipes added", show_detail(detail, true) |
|
242 | 242 | str = link_to("Bug #1", "/issues/1", :class => Issue.find(1).css_classes) |
|
243 | 243 | assert_equal "<strong>Precedes</strong> <i>#{str}: Cannot print recipes</i> added", |
|
244 | 244 | show_detail(detail, false) |
|
245 | 245 | end |
|
246 | 246 | |
|
247 | 247 | def test_show_detail_relation_added_with_inexistant_issue |
|
248 | 248 | inexistant_issue_number = 9999 |
|
249 | 249 | assert_nil Issue.find_by_id(inexistant_issue_number) |
|
250 | 250 | detail = JournalDetail.new(:property => 'relation', |
|
251 | 251 | :prop_key => 'precedes', |
|
252 | 252 | :value => inexistant_issue_number) |
|
253 | 253 | assert_equal "Precedes Issue ##{inexistant_issue_number} added", show_detail(detail, true) |
|
254 | 254 | assert_equal "<strong>Precedes</strong> <i>Issue ##{inexistant_issue_number}</i> added", show_detail(detail, false) |
|
255 | 255 | end |
|
256 | 256 | |
|
257 | 257 | def test_show_detail_relation_added_should_not_disclose_issue_that_is_not_visible |
|
258 | 258 | issue = Issue.generate!(:is_private => true) |
|
259 | 259 | detail = JournalDetail.new(:property => 'relation', |
|
260 | 260 | :prop_key => 'precedes', |
|
261 | 261 | :value => issue.id) |
|
262 | 262 | |
|
263 | 263 | assert_equal "Precedes Issue ##{issue.id} added", show_detail(detail, true) |
|
264 | 264 | assert_equal "<strong>Precedes</strong> <i>Issue ##{issue.id}</i> added", show_detail(detail, false) |
|
265 | 265 | end |
|
266 | 266 | |
|
267 | 267 | def test_show_detail_relation_deleted |
|
268 | 268 | detail = JournalDetail.new(:property => 'relation', |
|
269 | 269 | :prop_key => 'precedes', |
|
270 | 270 | :old_value => 1) |
|
271 | 271 | assert_equal "Precedes deleted (Bug #1: Cannot print recipes)", show_detail(detail, true) |
|
272 | 272 | str = link_to("Bug #1", |
|
273 | 273 | "/issues/1", |
|
274 | 274 | :class => Issue.find(1).css_classes) |
|
275 | 275 | assert_equal "<strong>Precedes</strong> deleted (<i>#{str}: Cannot print recipes</i>)", |
|
276 | 276 | show_detail(detail, false) |
|
277 | 277 | end |
|
278 | 278 | |
|
279 | 279 | def test_show_detail_relation_deleted_with_inexistant_issue |
|
280 | 280 | inexistant_issue_number = 9999 |
|
281 | 281 | assert_nil Issue.find_by_id(inexistant_issue_number) |
|
282 | 282 | detail = JournalDetail.new(:property => 'relation', |
|
283 | 283 | :prop_key => 'precedes', |
|
284 | 284 | :old_value => inexistant_issue_number) |
|
285 | 285 | assert_equal "Precedes deleted (Issue #9999)", show_detail(detail, true) |
|
286 | 286 | assert_equal "<strong>Precedes</strong> deleted (<i>Issue #9999</i>)", show_detail(detail, false) |
|
287 | 287 | end |
|
288 | 288 | |
|
289 | 289 | def test_show_detail_relation_deleted_should_not_disclose_issue_that_is_not_visible |
|
290 | 290 | issue = Issue.generate!(:is_private => true) |
|
291 | 291 | detail = JournalDetail.new(:property => 'relation', |
|
292 | 292 | :prop_key => 'precedes', |
|
293 | 293 | :old_value => issue.id) |
|
294 | 294 | |
|
295 | 295 | assert_equal "Precedes deleted (Issue ##{issue.id})", show_detail(detail, true) |
|
296 | 296 | assert_equal "<strong>Precedes</strong> deleted (<i>Issue ##{issue.id}</i>)", show_detail(detail, false) |
|
297 | 297 | end |
|
298 | 298 | |
|
299 | 299 | def test_details_to_strings_with_multiple_values_removed_from_custom_field |
|
300 | 300 | field = IssueCustomField.generate!(:name => 'User', :field_format => 'user', :multiple => true) |
|
301 | 301 | details = [] |
|
302 | 302 | details << JournalDetail.new(:property => 'cf', :prop_key => field.id.to_s, :old_value => '1', :value => nil) |
|
303 | 303 | details << JournalDetail.new(:property => 'cf', :prop_key => field.id.to_s, :old_value => '3', :value => nil) |
|
304 | 304 | |
|
305 | 305 | assert_equal ["User deleted (Dave Lopper, Redmine Admin)"], details_to_strings(details, true) |
|
306 | 306 | assert_equal ["<strong>User</strong> deleted (<del><i>Dave Lopper, Redmine Admin</i></del>)"], details_to_strings(details, false) |
|
307 | 307 | end |
|
308 | 308 | |
|
309 | 309 | def test_details_to_strings_with_multiple_values_added_to_custom_field |
|
310 | 310 | field = IssueCustomField.generate!(:name => 'User', :field_format => 'user', :multiple => true) |
|
311 | 311 | details = [] |
|
312 | 312 | details << JournalDetail.new(:property => 'cf', :prop_key => field.id.to_s, :old_value => nil, :value => '1') |
|
313 | 313 | details << JournalDetail.new(:property => 'cf', :prop_key => field.id.to_s, :old_value => nil, :value => '3') |
|
314 | 314 | |
|
315 | 315 | assert_equal ["User Dave Lopper, Redmine Admin added"], details_to_strings(details, true) |
|
316 | 316 | assert_equal ["<strong>User</strong> <i>Dave Lopper, Redmine Admin</i> added"], details_to_strings(details, false) |
|
317 | 317 | end |
|
318 | 318 | |
|
319 | 319 | def test_details_to_strings_with_multiple_values_added_and_removed_from_custom_field |
|
320 | 320 | field = IssueCustomField.generate!(:name => 'User', :field_format => 'user', :multiple => true) |
|
321 | 321 | details = [] |
|
322 | 322 | details << JournalDetail.new(:property => 'cf', :prop_key => field.id.to_s, :old_value => nil, :value => '1') |
|
323 | 323 | details << JournalDetail.new(:property => 'cf', :prop_key => field.id.to_s, :old_value => '2', :value => nil) |
|
324 | 324 | details << JournalDetail.new(:property => 'cf', :prop_key => field.id.to_s, :old_value => '3', :value => nil) |
|
325 | 325 | |
|
326 | 326 | assert_equal [ |
|
327 | 327 | "User Redmine Admin added", |
|
328 | 328 | "User deleted (Dave Lopper, John Smith)" |
|
329 | 329 | ], details_to_strings(details, true) |
|
330 | 330 | assert_equal [ |
|
331 | 331 | "<strong>User</strong> <i>Redmine Admin</i> added", |
|
332 | 332 | "<strong>User</strong> deleted (<del><i>Dave Lopper, John Smith</i></del>)" |
|
333 | 333 | ], details_to_strings(details, false) |
|
334 | 334 | end |
|
335 | 335 | |
|
336 | 336 | def test_find_name_by_reflection_should_return_nil_for_missing_record |
|
337 | 337 | assert_nil find_name_by_reflection('status', 99) |
|
338 | 338 | end |
|
339 | 339 | end |
@@ -1,43 +1,44 | |||
|
1 | 1 | # Redmine - project management software |
|
2 | 2 | # Copyright (C) 2006-2016 Jean-Philippe Lang |
|
3 | 3 | # |
|
4 | 4 | # This program is free software; you can redistribute it and/or |
|
5 | 5 | # modify it under the terms of the GNU General Public License |
|
6 | 6 | # as published by the Free Software Foundation; either version 2 |
|
7 | 7 | # of the License, or (at your option) any later version. |
|
8 | 8 | # |
|
9 | 9 | # This program is distributed in the hope that it will be useful, |
|
10 | 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 | 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 | 12 | # GNU General Public License for more details. |
|
13 | 13 | # |
|
14 | 14 | # You should have received a copy of the GNU General Public License |
|
15 | 15 | # along with this program; if not, write to the Free Software |
|
16 | 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
17 | 17 | |
|
18 | 18 | require File.expand_path('../../../test_helper', __FILE__) |
|
19 | 19 | |
|
20 | 20 | class MembersHelperTest < Redmine::HelperTest |
|
21 | 21 | include Redmine::I18n |
|
22 | 22 | include ERB::Util |
|
23 | 23 | include MembersHelper |
|
24 | include Rails.application.routes.url_helpers | |
|
24 | 25 | |
|
25 | 26 | fixtures :projects, :users, :members, :member_roles, |
|
26 | 27 | :trackers, :issue_statuses |
|
27 | 28 | |
|
28 | 29 | def test_render_principals_for_new_members |
|
29 | 30 | project = Project.generate! |
|
30 | 31 | |
|
31 | 32 | result = render_principals_for_new_members(project) |
|
32 | 33 | assert_select_in result, 'input[name=?][value="2"]', 'membership[user_ids][]' |
|
33 | 34 | end |
|
34 | 35 | |
|
35 | 36 | def test_render_principals_for_new_members_with_limited_results_should_paginate |
|
36 | 37 | project = Project.generate! |
|
37 | 38 | |
|
38 | 39 | result = render_principals_for_new_members(project, 3) |
|
39 | 40 | assert_select_in result, 'span.pagination' |
|
40 | 41 | assert_select_in result, 'span.pagination li.current span', :text => '1' |
|
41 | 42 | assert_select_in result, 'a[href=?]', "/projects/#{project.identifier}/memberships/autocomplete.js?page=2", :text => '2' |
|
42 | 43 | end |
|
43 | 44 | end |
@@ -1,498 +1,498 | |||
|
1 | 1 | # Redmine - project management software |
|
2 | 2 | # Copyright (C) 2006-2016 Jean-Philippe Lang |
|
3 | 3 | # |
|
4 | 4 | # This program is free software; you can redistribute it and/or |
|
5 | 5 | # modify it under the terms of the GNU General Public License |
|
6 | 6 | # as published by the Free Software Foundation; either version 2 |
|
7 | 7 | # of the License, or (at your option) any later version. |
|
8 | 8 | # |
|
9 | 9 | # This program is distributed in the hope that it will be useful, |
|
10 | 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 | 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 | 12 | # GNU General Public License for more details. |
|
13 | 13 | # |
|
14 | 14 | # You should have received a copy of the GNU General Public License |
|
15 | 15 | # along with this program; if not, write to the Free Software |
|
16 | 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
17 | 17 | |
|
18 | 18 | require File.expand_path('../../../../../test_helper', __FILE__) |
|
19 | 19 | |
|
20 |
class Redmine::Helpers::GanttHelperTest < |
|
|
20 | class Redmine::Helpers::GanttHelperTest < Redmine::HelperTest | |
|
21 | 21 | fixtures :projects, :trackers, :issue_statuses, |
|
22 | 22 | :enumerations, :users, :issue_categories |
|
23 | 23 | |
|
24 | 24 | include ProjectsHelper |
|
25 | 25 | include IssuesHelper |
|
26 | 26 | include ERB::Util |
|
27 | 27 | include Rails.application.routes.url_helpers |
|
28 | 28 | |
|
29 | 29 | def setup |
|
30 | 30 | setup_with_controller |
|
31 | 31 | User.current = User.find(1) |
|
32 | 32 | end |
|
33 | 33 | |
|
34 | 34 | def today |
|
35 | 35 | @today ||= Date.today |
|
36 | 36 | end |
|
37 | 37 | private :today |
|
38 | 38 | |
|
39 | 39 | def gantt_start |
|
40 | 40 | @gantt.date_from |
|
41 | 41 | end |
|
42 | 42 | |
|
43 | 43 | # Creates a Gantt chart for a 4 week span |
|
44 | 44 | def create_gantt(project=Project.generate!, options={}) |
|
45 | 45 | @project = project |
|
46 | 46 | @gantt = Redmine::Helpers::Gantt.new(options) |
|
47 | 47 | @gantt.project = @project |
|
48 | 48 | @gantt.query = IssueQuery.new(:project => @project, :name => 'Gantt') |
|
49 | 49 | @gantt.view = self |
|
50 | 50 | @gantt.instance_variable_set('@date_from', options[:date_from] || (today - 14)) |
|
51 | 51 | @gantt.instance_variable_set('@date_to', options[:date_to] || (today + 14)) |
|
52 | 52 | end |
|
53 | 53 | private :create_gantt |
|
54 | 54 | |
|
55 | 55 | test "#number_of_rows with one project should return the number of rows just for that project" do |
|
56 | 56 | p1, p2 = Project.generate!, Project.generate! |
|
57 | 57 | i1, i2 = Issue.generate!(:project => p1), Issue.generate!(:project => p2) |
|
58 | 58 | create_gantt(p1) |
|
59 | 59 | assert_equal 2, @gantt.number_of_rows |
|
60 | 60 | end |
|
61 | 61 | |
|
62 | 62 | test "#number_of_rows with no project should return the total number of rows for all the projects, resursively" do |
|
63 | 63 | p1, p2 = Project.generate!, Project.generate! |
|
64 | 64 | create_gantt(nil) |
|
65 | 65 | # fix the return value of #number_of_rows_on_project() to an arbitrary value |
|
66 | 66 | # so that we really only test #number_of_rows |
|
67 | 67 | @gantt.stubs(:number_of_rows_on_project).returns(7) |
|
68 | 68 | # also fix #projects because we want to test #number_of_rows in isolation |
|
69 | 69 | @gantt.stubs(:projects).returns(Project.all) |
|
70 | 70 | # actual test |
|
71 | 71 | assert_equal Project.count*7, @gantt.number_of_rows |
|
72 | 72 | end |
|
73 | 73 | |
|
74 | 74 | test "#number_of_rows should not exceed max_rows option" do |
|
75 | 75 | p = Project.generate! |
|
76 | 76 | 5.times do |
|
77 | 77 | Issue.generate!(:project => p) |
|
78 | 78 | end |
|
79 | 79 | create_gantt(p) |
|
80 | 80 | @gantt.render |
|
81 | 81 | assert_equal 6, @gantt.number_of_rows |
|
82 | 82 | assert !@gantt.truncated |
|
83 | 83 | create_gantt(p, :max_rows => 3) |
|
84 | 84 | @gantt.render |
|
85 | 85 | assert_equal 3, @gantt.number_of_rows |
|
86 | 86 | assert @gantt.truncated |
|
87 | 87 | end |
|
88 | 88 | |
|
89 | 89 | test "#number_of_rows_on_project should count 0 for an empty the project" do |
|
90 | 90 | create_gantt |
|
91 | 91 | assert_equal 0, @gantt.number_of_rows_on_project(@project) |
|
92 | 92 | end |
|
93 | 93 | |
|
94 | 94 | test "#number_of_rows_on_project should count the number of issues without a version" do |
|
95 | 95 | create_gantt |
|
96 | 96 | @project.issues << Issue.generate!(:project => @project, :fixed_version => nil) |
|
97 | 97 | assert_equal 2, @gantt.number_of_rows_on_project(@project) |
|
98 | 98 | end |
|
99 | 99 | |
|
100 | 100 | test "#number_of_rows_on_project should count the number of issues on versions, including cross-project" do |
|
101 | 101 | create_gantt |
|
102 | 102 | version = Version.generate! |
|
103 | 103 | @project.versions << version |
|
104 | 104 | @project.issues << Issue.generate!(:project => @project, :fixed_version => version) |
|
105 | 105 | assert_equal 3, @gantt.number_of_rows_on_project(@project) |
|
106 | 106 | end |
|
107 | 107 | |
|
108 | 108 | def setup_subjects |
|
109 | 109 | create_gantt |
|
110 | 110 | @project.enabled_module_names = [:issue_tracking] |
|
111 | 111 | @tracker = Tracker.generate! |
|
112 | 112 | @project.trackers << @tracker |
|
113 | 113 | @version = Version.generate!(:effective_date => (today + 7), :sharing => 'none') |
|
114 | 114 | @project.versions << @version |
|
115 | 115 | @issue = Issue.generate!(:fixed_version => @version, |
|
116 | 116 | :subject => "gantt#line_for_project", |
|
117 | 117 | :tracker => @tracker, |
|
118 | 118 | :project => @project, |
|
119 | 119 | :done_ratio => 30, |
|
120 | 120 | :start_date => (today - 1), |
|
121 | 121 | :due_date => (today + 7)) |
|
122 | 122 | @project.issues << @issue |
|
123 | 123 | end |
|
124 | 124 | private :setup_subjects |
|
125 | 125 | |
|
126 | 126 | # TODO: more of an integration test |
|
127 | 127 | test "#subjects project should be rendered" do |
|
128 | 128 | setup_subjects |
|
129 | 129 | @output_buffer = @gantt.subjects |
|
130 | 130 | assert_select "div.project-name a", /#{@project.name}/ |
|
131 | 131 | assert_select 'div.project-name[style*="left:4px"]' |
|
132 | 132 | end |
|
133 | 133 | |
|
134 | 134 | test "#subjects version should be rendered" do |
|
135 | 135 | setup_subjects |
|
136 | 136 | @output_buffer = @gantt.subjects |
|
137 | 137 | assert_select "div.version-name a", /#{@version.name}/ |
|
138 | 138 | assert_select 'div.version-name[style*="left:24px"]' |
|
139 | 139 | end |
|
140 | 140 | |
|
141 | 141 | test "#subjects version without assigned issues should not be rendered" do |
|
142 | 142 | setup_subjects |
|
143 | 143 | @version = Version.generate!(:effective_date => (today + 14), |
|
144 | 144 | :sharing => 'none', |
|
145 | 145 | :name => 'empty_version') |
|
146 | 146 | @project.versions << @version |
|
147 | 147 | @output_buffer = @gantt.subjects |
|
148 | 148 | assert_select "div.version-name a", :text => /#{@version.name}/, :count => 0 |
|
149 | 149 | end |
|
150 | 150 | |
|
151 | 151 | test "#subjects issue should be rendered" do |
|
152 | 152 | setup_subjects |
|
153 | 153 | @output_buffer = @gantt.subjects |
|
154 | 154 | assert_select "div.issue-subject", /#{@issue.subject}/ |
|
155 | 155 | assert_select 'div.issue-subject[style*="left:44px"]' |
|
156 | 156 | end |
|
157 | 157 | |
|
158 | 158 | test "#subjects issue assigned to a shared version of another project should be rendered" do |
|
159 | 159 | setup_subjects |
|
160 | 160 | p = Project.generate! |
|
161 | 161 | p.enabled_module_names = [:issue_tracking] |
|
162 | 162 | @shared_version = Version.generate!(:sharing => 'system') |
|
163 | 163 | p.versions << @shared_version |
|
164 | 164 | # Reassign the issue to a shared version of another project |
|
165 | 165 | @issue = Issue.generate!(:fixed_version => @shared_version, |
|
166 | 166 | :subject => "gantt#assigned_to_shared_version", |
|
167 | 167 | :tracker => @tracker, |
|
168 | 168 | :project => @project, |
|
169 | 169 | :done_ratio => 30, |
|
170 | 170 | :start_date => (today - 1), |
|
171 | 171 | :due_date => (today + 7)) |
|
172 | 172 | @project.issues << @issue |
|
173 | 173 | @output_buffer = @gantt.subjects |
|
174 | 174 | assert_select "div.issue-subject", /#{@issue.subject}/ |
|
175 | 175 | end |
|
176 | 176 | |
|
177 | 177 | test "#subjects issue with subtasks should indent subtasks" do |
|
178 | 178 | setup_subjects |
|
179 | 179 | attrs = {:project => @project, :tracker => @tracker, :fixed_version => @version} |
|
180 | 180 | @child1 = Issue.generate!( |
|
181 | 181 | attrs.merge(:subject => 'child1', |
|
182 | 182 | :parent_issue_id => @issue.id, |
|
183 | 183 | :start_date => (today - 1), |
|
184 | 184 | :due_date => (today + 2)) |
|
185 | 185 | ) |
|
186 | 186 | @child2 = Issue.generate!( |
|
187 | 187 | attrs.merge(:subject => 'child2', |
|
188 | 188 | :parent_issue_id => @issue.id, |
|
189 | 189 | :start_date => today, |
|
190 | 190 | :due_date => (today + 7)) |
|
191 | 191 | ) |
|
192 | 192 | @grandchild = Issue.generate!( |
|
193 | 193 | attrs.merge(:subject => 'grandchild', |
|
194 | 194 | :parent_issue_id => @child1.id, |
|
195 | 195 | :start_date => (today - 1), |
|
196 | 196 | :due_date => (today + 2)) |
|
197 | 197 | ) |
|
198 | 198 | @output_buffer = @gantt.subjects |
|
199 | 199 | # parent task 44px |
|
200 | 200 | assert_select 'div.issue-subject[style*="left:44px"]', /#{@issue.subject}/ |
|
201 | 201 | # children 64px |
|
202 | 202 | assert_select 'div.issue-subject[style*="left:64px"]', /child1/ |
|
203 | 203 | assert_select 'div.issue-subject[style*="left:64px"]', /child2/ |
|
204 | 204 | # grandchild 84px |
|
205 | 205 | assert_select 'div.issue-subject[style*="left:84px"]', /grandchild/, @output_buffer |
|
206 | 206 | end |
|
207 | 207 | |
|
208 | 208 | test "#lines" do |
|
209 | 209 | create_gantt |
|
210 | 210 | @project.enabled_module_names = [:issue_tracking] |
|
211 | 211 | @tracker = Tracker.generate! |
|
212 | 212 | @project.trackers << @tracker |
|
213 | 213 | @version = Version.generate!(:effective_date => (today + 7)) |
|
214 | 214 | @project.versions << @version |
|
215 | 215 | @issue = Issue.generate!(:fixed_version => @version, |
|
216 | 216 | :subject => "gantt#line_for_project", |
|
217 | 217 | :tracker => @tracker, |
|
218 | 218 | :project => @project, |
|
219 | 219 | :done_ratio => 30, |
|
220 | 220 | :start_date => (today - 1), |
|
221 | 221 | :due_date => (today + 7)) |
|
222 | 222 | @project.issues << @issue |
|
223 | 223 | @output_buffer = @gantt.lines |
|
224 | 224 | |
|
225 | 225 | assert_select "div.project.task_todo" |
|
226 | 226 | assert_select "div.project.starting" |
|
227 | 227 | assert_select "div.project.ending" |
|
228 | 228 | assert_select "div.label.project", /#{@project.name}/ |
|
229 | 229 | |
|
230 | 230 | assert_select "div.version.task_todo" |
|
231 | 231 | assert_select "div.version.starting" |
|
232 | 232 | assert_select "div.version.ending" |
|
233 | 233 | assert_select "div.label.version", /#{@version.name}/ |
|
234 | 234 | |
|
235 | 235 | assert_select "div.task_todo" |
|
236 | 236 | assert_select "div.task.label", /#{@issue.done_ratio}/ |
|
237 | 237 | assert_select "div.tooltip", /#{@issue.subject}/ |
|
238 | 238 | end |
|
239 | 239 | |
|
240 | 240 | test "#subject_for_project" do |
|
241 | 241 | create_gantt |
|
242 | 242 | @output_buffer = @gantt.subject_for_project(@project, :format => :html) |
|
243 | 243 | assert_select 'a[href=?]', "/projects/#{@project.identifier}", :text => /#{@project.name}/ |
|
244 | 244 | end |
|
245 | 245 | |
|
246 | 246 | test "#subject_for_project should style overdue projects" do |
|
247 | 247 | create_gantt |
|
248 | 248 | @project.stubs(:overdue?).returns(true) |
|
249 | 249 | @output_buffer = @gantt.subject_for_project(@project, :format => :html) |
|
250 | 250 | assert_select 'div span.project-overdue' |
|
251 | 251 | end |
|
252 | 252 | |
|
253 | 253 | test "#subject_for_version" do |
|
254 | 254 | create_gantt |
|
255 | 255 | version = Version.generate!(:name => 'Foo', :effective_date => today, :project => @project) |
|
256 | 256 | @output_buffer = @gantt.subject_for_version(version, :format => :html) |
|
257 | 257 | assert_select 'a[href=?]', "/versions/#{version.to_param}", :text => /Foo/ |
|
258 | 258 | end |
|
259 | 259 | |
|
260 | 260 | test "#subject_for_version should style overdue versions" do |
|
261 | 261 | create_gantt |
|
262 | 262 | version = Version.generate!(:name => 'Foo', :effective_date => today, :project => @project) |
|
263 | 263 | version.stubs(:overdue?).returns(true) |
|
264 | 264 | @output_buffer = @gantt.subject_for_version(version, :format => :html) |
|
265 | 265 | assert_select 'div span.version-overdue' |
|
266 | 266 | end |
|
267 | 267 | |
|
268 | 268 | test "#subject_for_version should style behind schedule versions" do |
|
269 | 269 | create_gantt |
|
270 | 270 | version = Version.generate!(:name => 'Foo', :effective_date => today, :project => @project) |
|
271 | 271 | version.stubs(:behind_schedule?).returns(true) |
|
272 | 272 | @output_buffer = @gantt.subject_for_version(version, :format => :html) |
|
273 | 273 | assert_select 'div span.version-behind-schedule' |
|
274 | 274 | end |
|
275 | 275 | |
|
276 | 276 | test "#subject_for_issue" do |
|
277 | 277 | create_gantt |
|
278 | 278 | issue = Issue.generate!(:project => @project) |
|
279 | 279 | @output_buffer = @gantt.subject_for_issue(issue, :format => :html) |
|
280 | 280 | assert_select 'div', :text => /#{issue.subject}/ |
|
281 | 281 | assert_select 'a[href=?]', "/issues/#{issue.to_param}", :text => /#{issue.tracker.name} ##{issue.id}/ |
|
282 | 282 | end |
|
283 | 283 | |
|
284 | 284 | test "#subject_for_issue should style overdue issues" do |
|
285 | 285 | create_gantt |
|
286 | 286 | issue = Issue.generate!(:project => @project) |
|
287 | 287 | issue.stubs(:overdue?).returns(true) |
|
288 | 288 | @output_buffer = @gantt.subject_for_issue(issue, :format => :html) |
|
289 | 289 | assert_select 'div span.issue-overdue' |
|
290 | 290 | end |
|
291 | 291 | |
|
292 | 292 | test "#subject should add an absolute positioned div" do |
|
293 | 293 | create_gantt |
|
294 | 294 | @output_buffer = @gantt.subject('subject', :format => :html) |
|
295 | 295 | assert_select "div[style*=absolute]", :text => 'subject' |
|
296 | 296 | end |
|
297 | 297 | |
|
298 | 298 | test "#subject should use the indent option to move the div to the right" do |
|
299 | 299 | create_gantt |
|
300 | 300 | @output_buffer = @gantt.subject('subject', :format => :html, :indent => 40) |
|
301 | 301 | assert_select 'div[style*="left:40"]' |
|
302 | 302 | end |
|
303 | 303 | |
|
304 | 304 | test "#line_for_project" do |
|
305 | 305 | create_gantt |
|
306 | 306 | @project.stubs(:start_date).returns(today - 7) |
|
307 | 307 | @project.stubs(:due_date).returns(today + 7) |
|
308 | 308 | @output_buffer = @gantt.line_for_project(@project, :format => :html) |
|
309 | 309 | assert_select "div.project.label", :text => @project.name |
|
310 | 310 | end |
|
311 | 311 | |
|
312 | 312 | test "#line_for_version" do |
|
313 | 313 | create_gantt |
|
314 | 314 | version = Version.generate!(:name => 'Foo', :project => @project) |
|
315 | 315 | version.stubs(:start_date).returns(today - 7) |
|
316 | 316 | version.stubs(:due_date).returns(today + 7) |
|
317 | 317 | version.stubs(:completed_percent).returns(30) |
|
318 | 318 | @output_buffer = @gantt.line_for_version(version, :format => :html) |
|
319 | 319 | assert_select "div.version.label", :text => /Foo/ |
|
320 | 320 | assert_select "div.version.label", :text => /30%/ |
|
321 | 321 | end |
|
322 | 322 | |
|
323 | 323 | test "#line_for_issue" do |
|
324 | 324 | create_gantt |
|
325 | 325 | issue = Issue.generate!(:project => @project, :start_date => today - 7, :due_date => today + 7, :done_ratio => 30) |
|
326 | 326 | @output_buffer = @gantt.line_for_issue(issue, :format => :html) |
|
327 | 327 | assert_select "div.task.label", :text => /#{issue.status.name}/ |
|
328 | 328 | assert_select "div.task.label", :text => /30%/ |
|
329 | 329 | assert_select "div.tooltip", /#{issue.subject}/ |
|
330 | 330 | end |
|
331 | 331 | |
|
332 | 332 | test "#line todo line should start from the starting point on the left" do |
|
333 | 333 | create_gantt |
|
334 | 334 | @output_buffer = @gantt.line(today - 7, today + 7, 30, false, 'line', :format => :html, :zoom => 4) |
|
335 | 335 | assert_select 'div.task_todo[style*="left:28px"]', 1 |
|
336 | 336 | end |
|
337 | 337 | |
|
338 | 338 | test "#line todo line should be the total width" do |
|
339 | 339 | create_gantt |
|
340 | 340 | @output_buffer = @gantt.line(today - 7, today + 7, 30, false, 'line', :format => :html, :zoom => 4) |
|
341 | 341 | assert_select 'div.task_todo[style*="width:58px"]', 1 |
|
342 | 342 | end |
|
343 | 343 | |
|
344 | 344 | test "#line late line should start from the starting point on the left" do |
|
345 | 345 | create_gantt |
|
346 | 346 | @output_buffer = @gantt.line(today - 7, today + 7, 30, false, 'line', :format => :html, :zoom => 4) |
|
347 | 347 | assert_select 'div.task_late[style*="left:28px"]', 1 |
|
348 | 348 | end |
|
349 | 349 | |
|
350 | 350 | test "#line late line should be the total delayed width" do |
|
351 | 351 | create_gantt |
|
352 | 352 | @output_buffer = @gantt.line(today - 7, today + 7, 30, false, 'line', :format => :html, :zoom => 4) |
|
353 | 353 | assert_select 'div.task_late[style*="width:30px"]', 1 |
|
354 | 354 | end |
|
355 | 355 | |
|
356 | 356 | test "#line done line should start from the starting point on the left" do |
|
357 | 357 | create_gantt |
|
358 | 358 | @output_buffer = @gantt.line(today - 7, today + 7, 30, false, 'line', :format => :html, :zoom => 4) |
|
359 | 359 | assert_select 'div.task_done[style*="left:28px"]', 1 |
|
360 | 360 | end |
|
361 | 361 | |
|
362 | 362 | test "#line done line should be the width for the done ratio" do |
|
363 | 363 | create_gantt |
|
364 | 364 | @output_buffer = @gantt.line(today - 7, today + 7, 30, false, 'line', :format => :html, :zoom => 4) |
|
365 | 365 | # 15 days * 4 px * 30% - 2 px for borders = 16 px |
|
366 | 366 | assert_select 'div.task_done[style*="width:16px"]', 1 |
|
367 | 367 | end |
|
368 | 368 | |
|
369 | 369 | test "#line done line should be the total width for 100% done ratio" do |
|
370 | 370 | create_gantt |
|
371 | 371 | @output_buffer = @gantt.line(today - 7, today + 7, 100, false, 'line', :format => :html, :zoom => 4) |
|
372 | 372 | # 15 days * 4 px - 2 px for borders = 58 px |
|
373 | 373 | assert_select 'div.task_done[style*="width:58px"]', 1 |
|
374 | 374 | end |
|
375 | 375 | |
|
376 | 376 | test "#line done line should be the total width for 100% done ratio with same start and end dates" do |
|
377 | 377 | create_gantt |
|
378 | 378 | @output_buffer = @gantt.line(today + 7, today + 7, 100, false, 'line', :format => :html, :zoom => 4) |
|
379 | 379 | assert_select 'div.task_done[style*="width:2px"]', 1 |
|
380 | 380 | end |
|
381 | 381 | |
|
382 | 382 | test "#line done line should not be the total done width if the gantt starts after start date" do |
|
383 | 383 | create_gantt |
|
384 | 384 | @output_buffer = @gantt.line(today - 16, today - 2, 30, false, 'line', :format => :html, :zoom => 4) |
|
385 | 385 | assert_select 'div.task_done[style*="left:0px"]', 1 |
|
386 | 386 | assert_select 'div.task_done[style*="width:8px"]', 1 |
|
387 | 387 | end |
|
388 | 388 | |
|
389 | 389 | test "#line starting marker should appear at the start date" do |
|
390 | 390 | create_gantt |
|
391 | 391 | @output_buffer = @gantt.line(today - 7, today + 7, 30, true, 'line', :format => :html, :zoom => 4) |
|
392 | 392 | assert_select "div.starting", 1 |
|
393 | 393 | assert_select 'div.starting[style*="left:28px"]', 1 |
|
394 | 394 | end |
|
395 | 395 | |
|
396 | 396 | test "#line starting marker should not appear if the start date is before gantt start date" do |
|
397 | 397 | create_gantt |
|
398 | 398 | @output_buffer = @gantt.line(gantt_start - 2, today + 7, 30, true, 'line', :format => :html, :zoom => 4) |
|
399 | 399 | assert_select "div.starting", 0 |
|
400 | 400 | end |
|
401 | 401 | |
|
402 | 402 | test "#line ending marker should appear at the end date" do |
|
403 | 403 | create_gantt |
|
404 | 404 | @output_buffer = @gantt.line(today - 7, today + 7, 30, true, 'line', :format => :html, :zoom => 4) |
|
405 | 405 | assert_select "div.ending", 1 |
|
406 | 406 | assert_select 'div.ending[style*="left:88px"]', 1 |
|
407 | 407 | end |
|
408 | 408 | |
|
409 | 409 | test "#line ending marker should not appear if the end date is before gantt start date" do |
|
410 | 410 | create_gantt |
|
411 | 411 | @output_buffer = @gantt.line(gantt_start - 30, gantt_start - 21, 30, true, 'line', :format => :html) |
|
412 | 412 | assert_select "div.ending", 0 |
|
413 | 413 | end |
|
414 | 414 | |
|
415 | 415 | test "#line label should appear at the far left, even if it's before gantt start date" do |
|
416 | 416 | create_gantt |
|
417 | 417 | @output_buffer = @gantt.line(gantt_start - 30, gantt_start - 21, 30, true, 'line', :format => :html) |
|
418 | 418 | assert_select "div.label", :text => 'line' |
|
419 | 419 | end |
|
420 | 420 | |
|
421 | 421 | def test_sort_issues_no_date |
|
422 | 422 | project = Project.generate! |
|
423 | 423 | issue1 = Issue.generate!(:subject => "test", :project => project) |
|
424 | 424 | issue2 = Issue.generate!(:subject => "test", :project => project) |
|
425 | 425 | assert issue1.root_id < issue2.root_id |
|
426 | 426 | child1 = Issue.generate!(:parent_issue_id => issue1.id, :subject => 'child', |
|
427 | 427 | :project => project) |
|
428 | 428 | child2 = Issue.generate!(:parent_issue_id => issue1.id, :subject => 'child', |
|
429 | 429 | :project => project) |
|
430 | 430 | child3 = Issue.generate!(:parent_issue_id => child1.id, :subject => 'child', |
|
431 | 431 | :project => project) |
|
432 | 432 | assert_equal child1.root_id, child2.root_id |
|
433 | 433 | assert child1.lft < child2.lft |
|
434 | 434 | assert child3.lft < child2.lft |
|
435 | 435 | issues = [child3, child2, child1, issue2, issue1] |
|
436 | 436 | Redmine::Helpers::Gantt.sort_issues!(issues) |
|
437 | 437 | assert_equal [issue1.id, child1.id, child3.id, child2.id, issue2.id], |
|
438 | 438 | issues.map{|v| v.id} |
|
439 | 439 | end |
|
440 | 440 | |
|
441 | 441 | def test_sort_issues_root_only |
|
442 | 442 | project = Project.generate! |
|
443 | 443 | issue1 = Issue.generate!(:subject => "test", :project => project) |
|
444 | 444 | issue2 = Issue.generate!(:subject => "test", :project => project) |
|
445 | 445 | issue3 = Issue.generate!(:subject => "test", :project => project, |
|
446 | 446 | :start_date => (today - 1)) |
|
447 | 447 | issue4 = Issue.generate!(:subject => "test", :project => project, |
|
448 | 448 | :start_date => (today - 2)) |
|
449 | 449 | issues = [issue4, issue3, issue2, issue1] |
|
450 | 450 | Redmine::Helpers::Gantt.sort_issues!(issues) |
|
451 | 451 | assert_equal [issue1.id, issue2.id, issue4.id, issue3.id], |
|
452 | 452 | issues.map{|v| v.id} |
|
453 | 453 | end |
|
454 | 454 | |
|
455 | 455 | def test_sort_issues_tree |
|
456 | 456 | project = Project.generate! |
|
457 | 457 | issue1 = Issue.generate!(:subject => "test", :project => project) |
|
458 | 458 | issue2 = Issue.generate!(:subject => "test", :project => project, |
|
459 | 459 | :start_date => (today - 2)) |
|
460 | 460 | issue1_child1 = |
|
461 | 461 | Issue.generate!(:parent_issue_id => issue1.id, :subject => 'child', |
|
462 | 462 | :project => project) |
|
463 | 463 | issue1_child2 = |
|
464 | 464 | Issue.generate!(:parent_issue_id => issue1.id, :subject => 'child', |
|
465 | 465 | :project => project, :start_date => (today - 10)) |
|
466 | 466 | issue1_child1_child1 = |
|
467 | 467 | Issue.generate!(:parent_issue_id => issue1_child1.id, :subject => 'child', |
|
468 | 468 | :project => project, :start_date => (today - 8)) |
|
469 | 469 | issue1_child1_child2 = |
|
470 | 470 | Issue.generate!(:parent_issue_id => issue1_child1.id, :subject => 'child', |
|
471 | 471 | :project => project, :start_date => (today - 9)) |
|
472 | 472 | issue1_child1_child1_logic = Redmine::Helpers::Gantt.sort_issue_logic(issue1_child1_child1) |
|
473 | 473 | assert_equal [[today - 10, issue1.id], [today - 9, issue1_child1.id], |
|
474 | 474 | [today - 8, issue1_child1_child1.id]], |
|
475 | 475 | issue1_child1_child1_logic |
|
476 | 476 | issue1_child1_child2_logic = Redmine::Helpers::Gantt.sort_issue_logic(issue1_child1_child2) |
|
477 | 477 | assert_equal [[today - 10, issue1.id], [today - 9, issue1_child1.id], |
|
478 | 478 | [today - 9, issue1_child1_child2.id]], |
|
479 | 479 | issue1_child1_child2_logic |
|
480 | 480 | issues = [issue1_child1_child2, issue1_child1_child1, issue1_child2, |
|
481 | 481 | issue1_child1, issue2, issue1] |
|
482 | 482 | Redmine::Helpers::Gantt.sort_issues!(issues) |
|
483 | 483 | assert_equal [issue1.id, issue1_child1.id, issue1_child2.id, |
|
484 | 484 | issue1_child1_child2.id, issue1_child1_child1.id, issue2.id], |
|
485 | 485 | issues.map{|v| v.id} |
|
486 | 486 | end |
|
487 | 487 | |
|
488 | 488 | def test_sort_versions |
|
489 | 489 | project = Project.generate! |
|
490 | 490 | versions = [] |
|
491 | 491 | versions << Version.create!(:project => project, :name => 'test1') |
|
492 | 492 | versions << Version.create!(:project => project, :name => 'test2', :effective_date => '2013-10-25') |
|
493 | 493 | versions << Version.create!(:project => project, :name => 'test3') |
|
494 | 494 | versions << Version.create!(:project => project, :name => 'test4', :effective_date => '2013-10-02') |
|
495 | 495 | |
|
496 | 496 | assert_equal versions.sort, Redmine::Helpers::Gantt.sort_versions!(versions.dup) |
|
497 | 497 | end |
|
498 | 498 | end |
@@ -1,341 +1,342 | |||
|
1 | 1 | # Redmine - project management software |
|
2 | 2 | # Copyright (C) 2006-2016 Jean-Philippe Lang |
|
3 | 3 | # |
|
4 | 4 | # This program is free software; you can redistribute it and/or |
|
5 | 5 | # modify it under the terms of the GNU General Public License |
|
6 | 6 | # as published by the Free Software Foundation; either version 2 |
|
7 | 7 | # of the License, or (at your option) any later version. |
|
8 | 8 | # |
|
9 | 9 | # This program is distributed in the hope that it will be useful, |
|
10 | 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 | 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 | 12 | # GNU General Public License for more details. |
|
13 | 13 | # |
|
14 | 14 | # You should have received a copy of the GNU General Public License |
|
15 | 15 | # along with this program; if not, write to the Free Software |
|
16 | 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
17 | 17 | |
|
18 | 18 | require File.expand_path('../../../../../test_helper', __FILE__) |
|
19 | 19 | |
|
20 |
class Redmine::MenuManager::MenuHelperTest < |
|
|
21 | ||
|
20 | class Redmine::MenuManager::MenuHelperTest < Redmine::HelperTest | |
|
22 | 21 | include Redmine::MenuManager::MenuHelper |
|
23 | 22 | include ERB::Util |
|
23 | include Rails.application.routes.url_helpers | |
|
24 | ||
|
24 | 25 | fixtures :users, :members, :projects, :enabled_modules, :roles, :member_roles |
|
25 | 26 | |
|
26 | 27 | def setup |
|
27 | 28 | setup_with_controller |
|
28 | 29 | # Stub the current menu item in the controller |
|
29 | 30 | def current_menu_item |
|
30 | 31 | :index |
|
31 | 32 | end |
|
32 | 33 | end |
|
33 | 34 | |
|
34 | 35 | def test_render_single_menu_node |
|
35 | 36 | node = Redmine::MenuManager::MenuItem.new(:testing, '/test', { }) |
|
36 | 37 | @output_buffer = render_single_menu_node(node, 'This is a test', node.url, false) |
|
37 | 38 | |
|
38 | 39 | assert_select("a.testing", "This is a test") |
|
39 | 40 | end |
|
40 | 41 | |
|
41 | 42 | def test_render_menu_node |
|
42 | 43 | single_node = Redmine::MenuManager::MenuItem.new(:single_node, '/test', { }) |
|
43 | 44 | @output_buffer = render_menu_node(single_node, nil) |
|
44 | 45 | |
|
45 | 46 | assert_select("li") do |
|
46 | 47 | assert_select("a.single-node", "Single node") |
|
47 | 48 | end |
|
48 | 49 | end |
|
49 | 50 | |
|
50 | 51 | def test_render_menu_node_with_symbol_as_url |
|
51 | 52 | node = Redmine::MenuManager::MenuItem.new(:testing, :issues_path) |
|
52 | 53 | @output_buffer = render_menu_node(node, nil) |
|
53 | 54 | |
|
54 | 55 | assert_select 'a[href="/issues"]', "Testing" |
|
55 | 56 | end |
|
56 | 57 | |
|
57 | 58 | def test_render_menu_node_with_symbol_as_url_and_project |
|
58 | 59 | node = Redmine::MenuManager::MenuItem.new(:testing, :project_issues_path) |
|
59 | 60 | @output_buffer = render_menu_node(node, Project.find(1)) |
|
60 | 61 | |
|
61 | 62 | assert_select 'a[href="/projects/ecookbook/issues"]', "Testing" |
|
62 | 63 | end |
|
63 | 64 | |
|
64 | 65 | def test_render_menu_node_with_nested_items |
|
65 | 66 | parent_node = Redmine::MenuManager::MenuItem.new(:parent_node, '/test', { }) |
|
66 | 67 | parent_node << Redmine::MenuManager::MenuItem.new(:child_one_node, '/test', { }) |
|
67 | 68 | parent_node << Redmine::MenuManager::MenuItem.new(:child_two_node, '/test', { }) |
|
68 | 69 | parent_node << |
|
69 | 70 | Redmine::MenuManager::MenuItem.new(:child_three_node, '/test', { }) << |
|
70 | 71 | Redmine::MenuManager::MenuItem.new(:child_three_inner_node, '/test', { }) |
|
71 | 72 | |
|
72 | 73 | @output_buffer = render_menu_node(parent_node, nil) |
|
73 | 74 | |
|
74 | 75 | assert_select("li") do |
|
75 | 76 | assert_select("a.parent-node", "Parent node") |
|
76 | 77 | assert_select("ul") do |
|
77 | 78 | assert_select("li a.child-one-node", "Child one node") |
|
78 | 79 | assert_select("li a.child-two-node", "Child two node") |
|
79 | 80 | assert_select("li") do |
|
80 | 81 | assert_select("a.child-three-node", "Child three node") |
|
81 | 82 | assert_select("ul") do |
|
82 | 83 | assert_select("li a.child-three-inner-node", "Child three inner node") |
|
83 | 84 | end |
|
84 | 85 | end |
|
85 | 86 | end |
|
86 | 87 | end |
|
87 | 88 | |
|
88 | 89 | end |
|
89 | 90 | |
|
90 | 91 | def test_render_menu_node_with_children |
|
91 | 92 | User.current = User.find(2) |
|
92 | 93 | |
|
93 | 94 | parent_node = Redmine::MenuManager::MenuItem.new(:parent_node, |
|
94 | 95 | '/test', |
|
95 | 96 | { |
|
96 | 97 | :children => Proc.new {|p| |
|
97 | 98 | children = [] |
|
98 | 99 | 3.times do |time| |
|
99 | 100 | children << Redmine::MenuManager::MenuItem.new("test_child_#{time}", |
|
100 | 101 | {:controller => 'issues', :action => 'index'}, |
|
101 | 102 | {}) |
|
102 | 103 | end |
|
103 | 104 | children |
|
104 | 105 | } |
|
105 | 106 | }) |
|
106 | 107 | @output_buffer = render_menu_node(parent_node, Project.find(1)) |
|
107 | 108 | |
|
108 | 109 | assert_select("li") do |
|
109 | 110 | assert_select("a.parent-node", "Parent node") |
|
110 | 111 | assert_select("ul") do |
|
111 | 112 | assert_select("li a.test-child-0", "Test child 0") |
|
112 | 113 | assert_select("li a.test-child-1", "Test child 1") |
|
113 | 114 | assert_select("li a.test-child-2", "Test child 2") |
|
114 | 115 | end |
|
115 | 116 | end |
|
116 | 117 | end |
|
117 | 118 | |
|
118 | 119 | def test_render_menu_node_with_nested_items_and_children |
|
119 | 120 | User.current = User.find(2) |
|
120 | 121 | |
|
121 | 122 | parent_node = Redmine::MenuManager::MenuItem.new(:parent_node, |
|
122 | 123 | {:controller => 'issues', :action => 'index'}, |
|
123 | 124 | { |
|
124 | 125 | :children => Proc.new {|p| |
|
125 | 126 | children = [] |
|
126 | 127 | 3.times do |time| |
|
127 | 128 | children << Redmine::MenuManager::MenuItem.new("test_child_#{time}", {:controller => 'issues', :action => 'index'}, {}) |
|
128 | 129 | end |
|
129 | 130 | children |
|
130 | 131 | } |
|
131 | 132 | }) |
|
132 | 133 | |
|
133 | 134 | parent_node << Redmine::MenuManager::MenuItem.new(:child_node, |
|
134 | 135 | {:controller => 'issues', :action => 'index'}, |
|
135 | 136 | { |
|
136 | 137 | :children => Proc.new {|p| |
|
137 | 138 | children = [] |
|
138 | 139 | 6.times do |time| |
|
139 | 140 | children << Redmine::MenuManager::MenuItem.new("test_dynamic_child_#{time}", {:controller => 'issues', :action => 'index'}, {}) |
|
140 | 141 | end |
|
141 | 142 | children |
|
142 | 143 | } |
|
143 | 144 | }) |
|
144 | 145 | |
|
145 | 146 | @output_buffer = render_menu_node(parent_node, Project.find(1)) |
|
146 | 147 | |
|
147 | 148 | assert_select("li") do |
|
148 | 149 | assert_select("a.parent-node", "Parent node") |
|
149 | 150 | assert_select("ul") do |
|
150 | 151 | assert_select("li a.child-node", "Child node") |
|
151 | 152 | assert_select("ul") do |
|
152 | 153 | assert_select("li a.test-dynamic-child-0", "Test dynamic child 0") |
|
153 | 154 | assert_select("li a.test-dynamic-child-1", "Test dynamic child 1") |
|
154 | 155 | assert_select("li a.test-dynamic-child-2", "Test dynamic child 2") |
|
155 | 156 | assert_select("li a.test-dynamic-child-3", "Test dynamic child 3") |
|
156 | 157 | assert_select("li a.test-dynamic-child-4", "Test dynamic child 4") |
|
157 | 158 | assert_select("li a.test-dynamic-child-5", "Test dynamic child 5") |
|
158 | 159 | end |
|
159 | 160 | assert_select("li a.test-child-0", "Test child 0") |
|
160 | 161 | assert_select("li a.test-child-1", "Test child 1") |
|
161 | 162 | assert_select("li a.test-child-2", "Test child 2") |
|
162 | 163 | end |
|
163 | 164 | end |
|
164 | 165 | end |
|
165 | 166 | |
|
166 | 167 | def test_render_menu_node_with_allowed_and_unallowed_unattached_children |
|
167 | 168 | User.current = User.find(2) |
|
168 | 169 | |
|
169 | 170 | parent_node = Redmine::MenuManager::MenuItem.new(:parent_node, |
|
170 | 171 | {:controller => 'issues', :action => 'index'}, |
|
171 | 172 | { |
|
172 | 173 | :children => Proc.new {|p| |
|
173 | 174 | [ |
|
174 | 175 | Redmine::MenuManager::MenuItem.new("test_child_allowed", {:controller => 'issues', :action => 'index'}, {}), |
|
175 | 176 | Redmine::MenuManager::MenuItem.new("test_child_unallowed", {:controller => 'issues', :action => 'unallowed'}, {}), |
|
176 | 177 | ] |
|
177 | 178 | } |
|
178 | 179 | }) |
|
179 | 180 | |
|
180 | 181 | @output_buffer = render_menu_node(parent_node, Project.find(1)) |
|
181 | 182 | |
|
182 | 183 | assert_select("li") do |
|
183 | 184 | assert_select("a.parent-node", "Parent node") |
|
184 | 185 | assert_select("ul.menu-children.unattached") do |
|
185 | 186 | assert_select("li a.test-child-allowed", "Test child allowed") |
|
186 | 187 | assert_select("li a.test-child-unallowed", false) |
|
187 | 188 | end |
|
188 | 189 | end |
|
189 | 190 | end |
|
190 | 191 | |
|
191 | 192 | def test_render_menu_node_with_allowed_and_unallowed_standard_children |
|
192 | 193 | User.current = User.find(6) |
|
193 | 194 | |
|
194 | 195 | Redmine::MenuManager.map :some_menu do |menu| |
|
195 | 196 | menu.push(:parent_node, {:controller => 'issues', :action => 'index'}, { }) |
|
196 | 197 | menu.push(:test_child_allowed, {:controller => 'issues', :action => 'index'}, {:parent => :parent_node}) |
|
197 | 198 | menu.push(:test_child_unallowed, {:controller => 'issues', :action => 'new'}, {:parent => :parent_node}) |
|
198 | 199 | end |
|
199 | 200 | |
|
200 | 201 | @output_buffer = render_menu(:some_menu, Project.find(1)) |
|
201 | 202 | |
|
202 | 203 | assert_select("li") do |
|
203 | 204 | assert_select("a.parent-node", "Parent node") |
|
204 | 205 | assert_select("ul.menu-children.unattached", false) |
|
205 | 206 | assert_select("ul.menu-children") do |
|
206 | 207 | assert_select("li a.test-child-allowed", "Test child allowed") |
|
207 | 208 | assert_select("li a.test-child-unallowed", false) |
|
208 | 209 | end |
|
209 | 210 | end |
|
210 | 211 | end |
|
211 | 212 | |
|
212 | 213 | def test_render_empty_virtual_menu_node_with_children |
|
213 | 214 | |
|
214 | 215 | # only empty item with no click target |
|
215 | 216 | Redmine::MenuManager.map :menu1 do |menu| |
|
216 | 217 | menu.push(:parent_node, nil, { }) |
|
217 | 218 | end |
|
218 | 219 | |
|
219 | 220 | # parent with unallowed unattached child |
|
220 | 221 | Redmine::MenuManager.map :menu2 do |menu| |
|
221 | 222 | menu.push(:parent_node, nil, {:children => Proc.new {|p| |
|
222 | 223 | [Redmine::MenuManager::MenuItem.new("test_child_unallowed", {:controller => 'issues', :action => 'new'}, {})] |
|
223 | 224 | } }) |
|
224 | 225 | end |
|
225 | 226 | |
|
226 | 227 | # parent with unallowed standard child |
|
227 | 228 | Redmine::MenuManager.map :menu3 do |menu| |
|
228 | 229 | menu.push(:parent_node, nil, {}) |
|
229 | 230 | menu.push(:test_child_unallowed, {:controller =>'issues', :action => 'new'}, {:parent => :parent_node}) |
|
230 | 231 | end |
|
231 | 232 | |
|
232 | 233 | # should not be displayed to anonymous |
|
233 | 234 | User.current = User.find(6) |
|
234 | 235 | assert_nil render_menu(:menu1, Project.find(1)) |
|
235 | 236 | assert_nil render_menu(:menu2, Project.find(1)) |
|
236 | 237 | assert_nil render_menu(:menu3, Project.find(1)) |
|
237 | 238 | |
|
238 | 239 | # should be displayed to an admin |
|
239 | 240 | User.current = User.find(1) |
|
240 | 241 | @output_buffer = render_menu(:menu2, Project.find(1)) |
|
241 | 242 | assert_select("ul li a.parent-node", "Parent node") |
|
242 | 243 | @output_buffer = render_menu(:menu3, Project.find(1)) |
|
243 | 244 | assert_select("ul li a.parent-node", "Parent node") |
|
244 | 245 | |
|
245 | 246 | end |
|
246 | 247 | |
|
247 | 248 | def test_render_menu_node_with_children_without_an_array |
|
248 | 249 | parent_node = Redmine::MenuManager::MenuItem.new(:parent_node, |
|
249 | 250 | '/test', |
|
250 | 251 | { |
|
251 | 252 | :children => Proc.new {|p| Redmine::MenuManager::MenuItem.new("test_child", "/testing", {})} |
|
252 | 253 | }) |
|
253 | 254 | |
|
254 | 255 | assert_raises Redmine::MenuManager::MenuError, ":children must be an array of MenuItems" do |
|
255 | 256 | @output_buffer = render_menu_node(parent_node, Project.find(1)) |
|
256 | 257 | end |
|
257 | 258 | end |
|
258 | 259 | |
|
259 | 260 | def test_render_menu_node_with_incorrect_children |
|
260 | 261 | parent_node = Redmine::MenuManager::MenuItem.new(:parent_node, |
|
261 | 262 | '/test', |
|
262 | 263 | { |
|
263 | 264 | :children => Proc.new {|p| ["a string"] } |
|
264 | 265 | }) |
|
265 | 266 | |
|
266 | 267 | assert_raises Redmine::MenuManager::MenuError, ":children must be an array of MenuItems" do |
|
267 | 268 | @output_buffer = render_menu_node(parent_node, Project.find(1)) |
|
268 | 269 | end |
|
269 | 270 | |
|
270 | 271 | end |
|
271 | 272 | |
|
272 | 273 | def test_menu_items_for_should_yield_all_items_if_passed_a_block |
|
273 | 274 | menu_name = :test_menu_items_for_should_yield_all_items_if_passed_a_block |
|
274 | 275 | Redmine::MenuManager.map menu_name do |menu| |
|
275 | 276 | menu.push(:a_menu, '/', { }) |
|
276 | 277 | menu.push(:a_menu_2, '/', { }) |
|
277 | 278 | menu.push(:a_menu_3, '/', { }) |
|
278 | 279 | end |
|
279 | 280 | |
|
280 | 281 | items_yielded = [] |
|
281 | 282 | menu_items_for(menu_name) do |item| |
|
282 | 283 | items_yielded << item |
|
283 | 284 | end |
|
284 | 285 | |
|
285 | 286 | assert_equal 3, items_yielded.size |
|
286 | 287 | end |
|
287 | 288 | |
|
288 | 289 | def test_menu_items_for_should_return_all_items |
|
289 | 290 | menu_name = :test_menu_items_for_should_return_all_items |
|
290 | 291 | Redmine::MenuManager.map menu_name do |menu| |
|
291 | 292 | menu.push(:a_menu, '/', { }) |
|
292 | 293 | menu.push(:a_menu_2, '/', { }) |
|
293 | 294 | menu.push(:a_menu_3, '/', { }) |
|
294 | 295 | end |
|
295 | 296 | |
|
296 | 297 | items = menu_items_for(menu_name) |
|
297 | 298 | assert_equal 3, items.size |
|
298 | 299 | end |
|
299 | 300 | |
|
300 | 301 | def test_menu_items_for_should_skip_unallowed_items_on_a_project |
|
301 | 302 | menu_name = :test_menu_items_for_should_skip_unallowed_items_on_a_project |
|
302 | 303 | Redmine::MenuManager.map menu_name do |menu| |
|
303 | 304 | menu.push(:a_menu, {:controller => 'issues', :action => 'index' }, { }) |
|
304 | 305 | menu.push(:a_menu_2, {:controller => 'issues', :action => 'index' }, { }) |
|
305 | 306 | menu.push(:unallowed, {:controller => 'issues', :action => 'unallowed' }, { }) |
|
306 | 307 | end |
|
307 | 308 | |
|
308 | 309 | User.current = User.find(2) |
|
309 | 310 | |
|
310 | 311 | items = menu_items_for(menu_name, Project.find(1)) |
|
311 | 312 | assert_equal 2, items.size |
|
312 | 313 | end |
|
313 | 314 | |
|
314 | 315 | def test_menu_items_for_should_skip_items_that_fail_the_permission |
|
315 | 316 | menu_name = :test_menu_items_for_should_skip_items_that_fail_the_permission |
|
316 | 317 | Redmine::MenuManager.map menu_name do |menu| |
|
317 | 318 | menu.push(:a_menu, :project_issues_path) |
|
318 | 319 | menu.push(:unallowed, :project_issues_path, :permission => :unallowed) |
|
319 | 320 | end |
|
320 | 321 | |
|
321 | 322 | User.current = User.find(2) |
|
322 | 323 | |
|
323 | 324 | items = menu_items_for(menu_name, Project.find(1)) |
|
324 | 325 | assert_equal 1, items.size |
|
325 | 326 | end |
|
326 | 327 | |
|
327 | 328 | def test_menu_items_for_should_skip_items_that_fail_the_conditions |
|
328 | 329 | menu_name = :test_menu_items_for_should_skip_items_that_fail_the_conditions |
|
329 | 330 | Redmine::MenuManager.map menu_name do |menu| |
|
330 | 331 | menu.push(:a_menu, {:controller => 'issues', :action => 'index' }, { }) |
|
331 | 332 | menu.push(:unallowed, |
|
332 | 333 | {:controller => 'issues', :action => 'index' }, |
|
333 | 334 | { :if => Proc.new { false }}) |
|
334 | 335 | end |
|
335 | 336 | |
|
336 | 337 | User.current = User.find(2) |
|
337 | 338 | |
|
338 | 339 | items = menu_items_for(menu_name, Project.find(1)) |
|
339 | 340 | assert_equal 1, items.size |
|
340 | 341 | end |
|
341 | 342 | end |
@@ -1,29 +1,30 | |||
|
1 | 1 | # Redmine - project management software |
|
2 | 2 | # Copyright (C) 2006-2016 Jean-Philippe Lang |
|
3 | 3 | # |
|
4 | 4 | # This program is free software; you can redistribute it and/or |
|
5 | 5 | # modify it under the terms of the GNU General Public License |
|
6 | 6 | # as published by the Free Software Foundation; either version 2 |
|
7 | 7 | # of the License, or (at your option) any later version. |
|
8 | 8 | # |
|
9 | 9 | # This program is distributed in the hope that it will be useful, |
|
10 | 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 | 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 | 12 | # GNU General Public License for more details. |
|
13 | 13 | # |
|
14 | 14 | # You should have received a copy of the GNU General Public License |
|
15 | 15 | # along with this program; if not, write to the Free Software |
|
16 | 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
17 | 17 | |
|
18 | 18 | require File.expand_path('../../../../../test_helper', __FILE__) |
|
19 | 19 | |
|
20 |
class Redmine::Views::LabelledFormBuilderTest < |
|
|
20 | class Redmine::Views::LabelledFormBuilderTest < Redmine::HelperTest | |
|
21 | include Rails.application.routes.url_helpers | |
|
21 | 22 | |
|
22 | 23 | def test_label_should_output_one_element |
|
23 | 24 | set_language_if_valid 'en' |
|
24 | 25 | labelled_form_for(Issue.new) do |f| |
|
25 | 26 | output = f.label :subject |
|
26 | 27 | assert_equal output, '<label for="issue_subject">Subject</label>' |
|
27 | 28 | end |
|
28 | 29 | end |
|
29 | 30 | end |
@@ -1,401 +1,402 | |||
|
1 | 1 | # Redmine - project management software |
|
2 | 2 | # Copyright (C) 2006-2016 Jean-Philippe Lang |
|
3 | 3 | # |
|
4 | 4 | # This program is free software; you can redistribute it and/or |
|
5 | 5 | # modify it under the terms of the GNU General Public License |
|
6 | 6 | # as published by the Free Software Foundation; either version 2 |
|
7 | 7 | # of the License, or (at your option) any later version. |
|
8 | 8 | # |
|
9 | 9 | # This program is distributed in the hope that it will be useful, |
|
10 | 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 | 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 | 12 | # GNU General Public License for more details. |
|
13 | 13 | # |
|
14 | 14 | # You should have received a copy of the GNU General Public License |
|
15 | 15 | # along with this program; if not, write to the Free Software |
|
16 | 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
17 | 17 | |
|
18 | 18 | require File.expand_path('../../../../../test_helper', __FILE__) |
|
19 | 19 | |
|
20 |
class Redmine::WikiFormatting::MacrosTest < |
|
|
20 | class Redmine::WikiFormatting::MacrosTest < Redmine::HelperTest | |
|
21 | 21 | include ApplicationHelper |
|
22 | 22 | include ActionView::Helpers::TextHelper |
|
23 | 23 | include ActionView::Helpers::SanitizeHelper |
|
24 | 24 | include ERB::Util |
|
25 | include Rails.application.routes.url_helpers | |
|
25 | 26 | extend ActionView::Helpers::SanitizeHelper::ClassMethods |
|
26 | 27 | |
|
27 | 28 | fixtures :projects, :roles, :enabled_modules, :users, |
|
28 | 29 | :repositories, :changesets, |
|
29 | 30 | :trackers, :issue_statuses, :issues, |
|
30 | 31 | :versions, :documents, |
|
31 | 32 | :wikis, :wiki_pages, :wiki_contents, |
|
32 | 33 | :boards, :messages, |
|
33 | 34 | :attachments |
|
34 | 35 | |
|
35 | 36 | def setup |
|
36 | 37 | super |
|
37 | 38 | @project = nil |
|
38 | 39 | end |
|
39 | 40 | |
|
40 | 41 | def teardown |
|
41 | 42 | end |
|
42 | 43 | |
|
43 | 44 | def test_macro_registration |
|
44 | 45 | Redmine::WikiFormatting::Macros.register do |
|
45 | 46 | macro :foo do |obj, args| |
|
46 | 47 | "Foo: #{args.size} (#{args.join(',')}) (#{args.class.name})" |
|
47 | 48 | end |
|
48 | 49 | end |
|
49 | 50 | |
|
50 | 51 | assert_equal '<p>Foo: 0 () (Array)</p>', textilizable("{{foo}}") |
|
51 | 52 | assert_equal '<p>Foo: 0 () (Array)</p>', textilizable("{{foo()}}") |
|
52 | 53 | assert_equal '<p>Foo: 1 (arg1) (Array)</p>', textilizable("{{foo(arg1)}}") |
|
53 | 54 | assert_equal '<p>Foo: 2 (arg1,arg2) (Array)</p>', textilizable("{{foo(arg1, arg2)}}") |
|
54 | 55 | end |
|
55 | 56 | |
|
56 | 57 | def test_macro_registration_parse_args_set_to_false_should_disable_arguments_parsing |
|
57 | 58 | Redmine::WikiFormatting::Macros.register do |
|
58 | 59 | macro :bar, :parse_args => false do |obj, args| |
|
59 | 60 | "Bar: (#{args}) (#{args.class.name})" |
|
60 | 61 | end |
|
61 | 62 | end |
|
62 | 63 | |
|
63 | 64 | assert_equal '<p>Bar: (args, more args) (String)</p>', textilizable("{{bar(args, more args)}}") |
|
64 | 65 | assert_equal '<p>Bar: () (String)</p>', textilizable("{{bar}}") |
|
65 | 66 | assert_equal '<p>Bar: () (String)</p>', textilizable("{{bar()}}") |
|
66 | 67 | end |
|
67 | 68 | |
|
68 | 69 | def test_macro_registration_with_3_args_should_receive_text_argument |
|
69 | 70 | Redmine::WikiFormatting::Macros.register do |
|
70 | 71 | macro :baz do |obj, args, text| |
|
71 | 72 | "Baz: (#{args.join(',')}) (#{text.class.name}) (#{text})" |
|
72 | 73 | end |
|
73 | 74 | end |
|
74 | 75 | |
|
75 | 76 | assert_equal "<p>Baz: () (NilClass) ()</p>", textilizable("{{baz}}") |
|
76 | 77 | assert_equal "<p>Baz: () (NilClass) ()</p>", textilizable("{{baz()}}") |
|
77 | 78 | assert_equal "<p>Baz: () (String) (line1\nline2)</p>", textilizable("{{baz()\nline1\nline2\n}}") |
|
78 | 79 | assert_equal "<p>Baz: (arg1,arg2) (String) (line1\nline2)</p>", textilizable("{{baz(arg1, arg2)\nline1\nline2\n}}") |
|
79 | 80 | end |
|
80 | 81 | |
|
81 | 82 | def test_macro_name_with_upper_case |
|
82 | 83 | Redmine::WikiFormatting::Macros.macro(:UpperCase) {|obj, args| "Upper"} |
|
83 | 84 | |
|
84 | 85 | assert_equal "<p>Upper</p>", textilizable("{{UpperCase}}") |
|
85 | 86 | end |
|
86 | 87 | |
|
87 | 88 | def test_multiple_macros_on_the_same_line |
|
88 | 89 | Redmine::WikiFormatting::Macros.macro :foo do |obj, args| |
|
89 | 90 | args.any? ? "args: #{args.join(',')}" : "no args" |
|
90 | 91 | end |
|
91 | 92 | |
|
92 | 93 | assert_equal '<p>no args no args</p>', textilizable("{{foo}} {{foo}}") |
|
93 | 94 | assert_equal '<p>args: a,b no args</p>', textilizable("{{foo(a,b)}} {{foo}}") |
|
94 | 95 | assert_equal '<p>args: a,b args: c,d</p>', textilizable("{{foo(a,b)}} {{foo(c,d)}}") |
|
95 | 96 | assert_equal '<p>no args args: c,d</p>', textilizable("{{foo}} {{foo(c,d)}}") |
|
96 | 97 | end |
|
97 | 98 | |
|
98 | 99 | def test_macro_should_receive_the_object_as_argument_when_with_object_and_attribute |
|
99 | 100 | issue = Issue.find(1) |
|
100 | 101 | issue.description = "{{hello_world}}" |
|
101 | 102 | assert_equal '<p>Hello world! Object: Issue, Called with no argument and no block of text.</p>', textilizable(issue, :description) |
|
102 | 103 | end |
|
103 | 104 | |
|
104 | 105 | def test_macro_should_receive_the_object_as_argument_when_called_with_object_option |
|
105 | 106 | text = "{{hello_world}}" |
|
106 | 107 | assert_equal '<p>Hello world! Object: Issue, Called with no argument and no block of text.</p>', textilizable(text, :object => Issue.find(1)) |
|
107 | 108 | end |
|
108 | 109 | |
|
109 | 110 | def test_extract_macro_options_should_with_args |
|
110 | 111 | options = extract_macro_options(["arg1", "arg2"], :foo, :size) |
|
111 | 112 | assert_equal([["arg1", "arg2"], {}], options) |
|
112 | 113 | end |
|
113 | 114 | |
|
114 | 115 | def test_extract_macro_options_should_with_options |
|
115 | 116 | options = extract_macro_options(["foo=bar", "size=2"], :foo, :size) |
|
116 | 117 | assert_equal([[], {:foo => "bar", :size => "2"}], options) |
|
117 | 118 | end |
|
118 | 119 | |
|
119 | 120 | def test_extract_macro_options_should_with_args_and_options |
|
120 | 121 | options = extract_macro_options(["arg1", "arg2", "foo=bar", "size=2"], :foo, :size) |
|
121 | 122 | assert_equal([["arg1", "arg2"], {:foo => "bar", :size => "2"}], options) |
|
122 | 123 | end |
|
123 | 124 | |
|
124 | 125 | def test_extract_macro_options_should_parse_options_lazily |
|
125 | 126 | options = extract_macro_options(["params=x=1&y=2"], :params) |
|
126 | 127 | assert_equal([[], {:params => "x=1&y=2"}], options) |
|
127 | 128 | end |
|
128 | 129 | |
|
129 | 130 | def test_macro_exception_should_be_displayed |
|
130 | 131 | Redmine::WikiFormatting::Macros.macro :exception do |obj, args| |
|
131 | 132 | raise "My message" |
|
132 | 133 | end |
|
133 | 134 | |
|
134 | 135 | text = "{{exception}}" |
|
135 | 136 | assert_include '<div class="flash error">Error executing the <strong>exception</strong> macro (My message)</div>', textilizable(text) |
|
136 | 137 | end |
|
137 | 138 | |
|
138 | 139 | def test_macro_arguments_should_not_be_parsed_by_formatters |
|
139 | 140 | text = '{{hello_world(http://www.redmine.org, #1)}}' |
|
140 | 141 | assert_include 'Arguments: http://www.redmine.org, #1', textilizable(text) |
|
141 | 142 | end |
|
142 | 143 | |
|
143 | 144 | def test_exclamation_mark_should_not_run_macros |
|
144 | 145 | text = "!{{hello_world}}" |
|
145 | 146 | assert_equal '<p>{{hello_world}}</p>', textilizable(text) |
|
146 | 147 | end |
|
147 | 148 | |
|
148 | 149 | def test_exclamation_mark_should_escape_macros |
|
149 | 150 | text = "!{{hello_world(<tag>)}}" |
|
150 | 151 | assert_equal '<p>{{hello_world(<tag>)}}</p>', textilizable(text) |
|
151 | 152 | end |
|
152 | 153 | |
|
153 | 154 | def test_unknown_macros_should_not_be_replaced |
|
154 | 155 | text = "{{unknown}}" |
|
155 | 156 | assert_equal '<p>{{unknown}}</p>', textilizable(text) |
|
156 | 157 | end |
|
157 | 158 | |
|
158 | 159 | def test_unknown_macros_should_parsed_as_text |
|
159 | 160 | text = "{{unknown(*test*)}}" |
|
160 | 161 | assert_equal '<p>{{unknown(<strong>test</strong>)}}</p>', textilizable(text) |
|
161 | 162 | end |
|
162 | 163 | |
|
163 | 164 | def test_unknown_macros_should_be_escaped |
|
164 | 165 | text = "{{unknown(<tag>)}}" |
|
165 | 166 | assert_equal '<p>{{unknown(<tag>)}}</p>', textilizable(text) |
|
166 | 167 | end |
|
167 | 168 | |
|
168 | 169 | def test_html_safe_macro_output_should_not_be_escaped |
|
169 | 170 | Redmine::WikiFormatting::Macros.macro :safe_macro do |obj, args| |
|
170 | 171 | "<tag>".html_safe |
|
171 | 172 | end |
|
172 | 173 | assert_equal '<p><tag></p>', textilizable("{{safe_macro}}") |
|
173 | 174 | end |
|
174 | 175 | |
|
175 | 176 | def test_macro_hello_world |
|
176 | 177 | text = "{{hello_world}}" |
|
177 | 178 | assert textilizable(text).match(/Hello world!/) |
|
178 | 179 | end |
|
179 | 180 | |
|
180 | 181 | def test_macro_hello_world_should_escape_arguments |
|
181 | 182 | text = "{{hello_world(<tag>)}}" |
|
182 | 183 | assert_include 'Arguments: <tag>', textilizable(text) |
|
183 | 184 | end |
|
184 | 185 | |
|
185 | 186 | def test_macro_macro_list |
|
186 | 187 | text = "{{macro_list}}" |
|
187 | 188 | assert_match %r{<code>hello_world</code>}, textilizable(text) |
|
188 | 189 | end |
|
189 | 190 | |
|
190 | 191 | def test_macro_include |
|
191 | 192 | @project = Project.find(1) |
|
192 | 193 | # include a page of the current project wiki |
|
193 | 194 | text = "{{include(Another page)}}" |
|
194 | 195 | assert_include 'This is a link to a ticket', textilizable(text) |
|
195 | 196 | |
|
196 | 197 | @project = nil |
|
197 | 198 | # include a page of a specific project wiki |
|
198 | 199 | text = "{{include(ecookbook:Another page)}}" |
|
199 | 200 | assert_include 'This is a link to a ticket', textilizable(text) |
|
200 | 201 | |
|
201 | 202 | text = "{{include(ecookbook:)}}" |
|
202 | 203 | assert_include 'CookBook documentation', textilizable(text) |
|
203 | 204 | |
|
204 | 205 | text = "{{include(unknowidentifier:somepage)}}" |
|
205 | 206 | assert_include 'Page not found', textilizable(text) |
|
206 | 207 | end |
|
207 | 208 | |
|
208 | 209 | def test_macro_collapse |
|
209 | 210 | text = "{{collapse\n*Collapsed* block of text\n}}" |
|
210 | 211 | with_locale 'en' do |
|
211 | 212 | result = textilizable(text) |
|
212 | 213 | |
|
213 | 214 | assert_select_in result, 'div.collapsed-text' |
|
214 | 215 | assert_select_in result, 'strong', :text => 'Collapsed' |
|
215 | 216 | assert_select_in result, 'a.collapsible.collapsed', :text => 'Show' |
|
216 | 217 | assert_select_in result, 'a.collapsible', :text => 'Hide' |
|
217 | 218 | end |
|
218 | 219 | end |
|
219 | 220 | |
|
220 | 221 | def test_macro_collapse_with_one_arg |
|
221 | 222 | text = "{{collapse(Example)\n*Collapsed* block of text\n}}" |
|
222 | 223 | result = textilizable(text) |
|
223 | 224 | |
|
224 | 225 | assert_select_in result, 'div.collapsed-text' |
|
225 | 226 | assert_select_in result, 'strong', :text => 'Collapsed' |
|
226 | 227 | assert_select_in result, 'a.collapsible.collapsed', :text => 'Example' |
|
227 | 228 | assert_select_in result, 'a.collapsible', :text => 'Example' |
|
228 | 229 | end |
|
229 | 230 | |
|
230 | 231 | def test_macro_collapse_with_two_args |
|
231 | 232 | text = "{{collapse(Show example, Hide example)\n*Collapsed* block of text\n}}" |
|
232 | 233 | result = textilizable(text) |
|
233 | 234 | |
|
234 | 235 | assert_select_in result, 'div.collapsed-text' |
|
235 | 236 | assert_select_in result, 'strong', :text => 'Collapsed' |
|
236 | 237 | assert_select_in result, 'a.collapsible.collapsed', :text => 'Show example' |
|
237 | 238 | assert_select_in result, 'a.collapsible', :text => 'Hide example' |
|
238 | 239 | end |
|
239 | 240 | |
|
240 | 241 | def test_macro_collapse_should_not_break_toc |
|
241 | 242 | text = <<-RAW |
|
242 | 243 | {{toc}} |
|
243 | 244 | |
|
244 | 245 | h1. Title |
|
245 | 246 | |
|
246 | 247 | {{collapse(Show example, Hide example) |
|
247 | 248 | h2. Heading |
|
248 | 249 | }}" |
|
249 | 250 | RAW |
|
250 | 251 | |
|
251 | 252 | expected_toc = '<ul class="toc"><li><a href="#Title">Title</a><ul><li><a href="#Heading">Heading</a></li></ul></li></ul>' |
|
252 | 253 | |
|
253 | 254 | assert_include expected_toc, textilizable(text).gsub(/[\r\n]/, '') |
|
254 | 255 | end |
|
255 | 256 | |
|
256 | 257 | def test_macro_child_pages |
|
257 | 258 | expected = "<p><ul class=\"pages-hierarchy\">\n" + |
|
258 | 259 | "<li><a href=\"/projects/ecookbook/wiki/Child_1\">Child 1</a>\n" + |
|
259 | 260 | "<ul class=\"pages-hierarchy\">\n<li><a href=\"/projects/ecookbook/wiki/Child_1_1\">Child 1 1</a></li>\n</ul>\n</li>\n" + |
|
260 | 261 | "<li><a href=\"/projects/ecookbook/wiki/Child_2\">Child 2</a></li>\n" + |
|
261 | 262 | "</ul>\n</p>" |
|
262 | 263 | |
|
263 | 264 | @project = Project.find(1) |
|
264 | 265 | # child pages of the current wiki page |
|
265 | 266 | assert_equal expected, textilizable("{{child_pages}}", :object => WikiPage.find(2).content) |
|
266 | 267 | # child pages of another page |
|
267 | 268 | assert_equal expected, textilizable("{{child_pages(Another_page)}}", :object => WikiPage.find(1).content) |
|
268 | 269 | |
|
269 | 270 | @project = Project.find(2) |
|
270 | 271 | assert_equal expected, textilizable("{{child_pages(ecookbook:Another_page)}}", :object => WikiPage.find(1).content) |
|
271 | 272 | end |
|
272 | 273 | |
|
273 | 274 | def test_macro_child_pages_with_parent_option |
|
274 | 275 | expected = "<p><ul class=\"pages-hierarchy\">\n" + |
|
275 | 276 | "<li><a href=\"/projects/ecookbook/wiki/Another_page\">Another page</a>\n" + |
|
276 | 277 | "<ul class=\"pages-hierarchy\">\n" + |
|
277 | 278 | "<li><a href=\"/projects/ecookbook/wiki/Child_1\">Child 1</a>\n" + |
|
278 | 279 | "<ul class=\"pages-hierarchy\">\n<li><a href=\"/projects/ecookbook/wiki/Child_1_1\">Child 1 1</a></li>\n</ul>\n</li>\n" + |
|
279 | 280 | "<li><a href=\"/projects/ecookbook/wiki/Child_2\">Child 2</a></li>\n" + |
|
280 | 281 | "</ul>\n</li>\n</ul>\n</p>" |
|
281 | 282 | |
|
282 | 283 | @project = Project.find(1) |
|
283 | 284 | # child pages of the current wiki page |
|
284 | 285 | assert_equal expected, textilizable("{{child_pages(parent=1)}}", :object => WikiPage.find(2).content) |
|
285 | 286 | # child pages of another page |
|
286 | 287 | assert_equal expected, textilizable("{{child_pages(Another_page, parent=1)}}", :object => WikiPage.find(1).content) |
|
287 | 288 | |
|
288 | 289 | @project = Project.find(2) |
|
289 | 290 | assert_equal expected, textilizable("{{child_pages(ecookbook:Another_page, parent=1)}}", :object => WikiPage.find(1).content) |
|
290 | 291 | end |
|
291 | 292 | |
|
292 | 293 | def test_macro_child_pages_with_depth_option |
|
293 | 294 | expected = "<p><ul class=\"pages-hierarchy\">\n" + |
|
294 | 295 | "<li><a href=\"/projects/ecookbook/wiki/Child_1\">Child 1</a></li>\n" + |
|
295 | 296 | "<li><a href=\"/projects/ecookbook/wiki/Child_2\">Child 2</a></li>\n" + |
|
296 | 297 | "</ul>\n</p>" |
|
297 | 298 | |
|
298 | 299 | @project = Project.find(1) |
|
299 | 300 | assert_equal expected, textilizable("{{child_pages(depth=1)}}", :object => WikiPage.find(2).content) |
|
300 | 301 | end |
|
301 | 302 | |
|
302 | 303 | def test_macro_child_pages_without_wiki_page_should_fail |
|
303 | 304 | assert_match /can be called from wiki pages only/, textilizable("{{child_pages}}") |
|
304 | 305 | end |
|
305 | 306 | |
|
306 | 307 | def test_macro_thumbnail |
|
307 | 308 | link = link_to('<img alt="testfile.PNG" src="/attachments/thumbnail/17" />'.html_safe, |
|
308 | 309 | "/attachments/17", |
|
309 | 310 | :class => "thumbnail", |
|
310 | 311 | :title => "testfile.PNG") |
|
311 | 312 | assert_equal "<p>#{link}</p>", |
|
312 | 313 | textilizable("{{thumbnail(testfile.png)}}", :object => Issue.find(14)) |
|
313 | 314 | end |
|
314 | 315 | |
|
315 | 316 | def test_macro_thumbnail_with_full_path |
|
316 | 317 | link = link_to('<img alt="testfile.PNG" src="http://test.host/attachments/thumbnail/17" />'.html_safe, |
|
317 | 318 | "http://test.host/attachments/17", |
|
318 | 319 | :class => "thumbnail", |
|
319 | 320 | :title => "testfile.PNG") |
|
320 | 321 | assert_equal "<p>#{link}</p>", |
|
321 | 322 | textilizable("{{thumbnail(testfile.png)}}", :object => Issue.find(14), :only_path => false) |
|
322 | 323 | end |
|
323 | 324 | |
|
324 | 325 | def test_macro_thumbnail_with_size |
|
325 | 326 | link = link_to('<img alt="testfile.PNG" src="/attachments/thumbnail/17/200" />'.html_safe, |
|
326 | 327 | "/attachments/17", |
|
327 | 328 | :class => "thumbnail", |
|
328 | 329 | :title => "testfile.PNG") |
|
329 | 330 | assert_equal "<p>#{link}</p>", |
|
330 | 331 | textilizable("{{thumbnail(testfile.png, size=200)}}", :object => Issue.find(14)) |
|
331 | 332 | end |
|
332 | 333 | |
|
333 | 334 | def test_macro_thumbnail_with_title |
|
334 | 335 | link = link_to('<img alt="testfile.PNG" src="/attachments/thumbnail/17" />'.html_safe, |
|
335 | 336 | "/attachments/17", |
|
336 | 337 | :class => "thumbnail", |
|
337 | 338 | :title => "Cool image") |
|
338 | 339 | assert_equal "<p>#{link}</p>", |
|
339 | 340 | textilizable("{{thumbnail(testfile.png, title=Cool image)}}", :object => Issue.find(14)) |
|
340 | 341 | end |
|
341 | 342 | |
|
342 | 343 | def test_macro_thumbnail_with_invalid_filename_should_fail |
|
343 | 344 | assert_include 'test.png not found', |
|
344 | 345 | textilizable("{{thumbnail(test.png)}}", :object => Issue.find(14)) |
|
345 | 346 | end |
|
346 | 347 | |
|
347 | 348 | def test_macros_should_not_be_executed_in_pre_tags |
|
348 | 349 | text = <<-RAW |
|
349 | 350 | {{hello_world(foo)}} |
|
350 | 351 | |
|
351 | 352 | <pre> |
|
352 | 353 | {{hello_world(pre)}} |
|
353 | 354 | !{{hello_world(pre)}} |
|
354 | 355 | </pre> |
|
355 | 356 | |
|
356 | 357 | {{hello_world(bar)}} |
|
357 | 358 | RAW |
|
358 | 359 | |
|
359 | 360 | expected = <<-EXPECTED |
|
360 | 361 | <p>Hello world! Object: NilClass, Arguments: foo and no block of text.</p> |
|
361 | 362 | |
|
362 | 363 | <pre> |
|
363 | 364 | {{hello_world(pre)}} |
|
364 | 365 | !{{hello_world(pre)}} |
|
365 | 366 | </pre> |
|
366 | 367 | |
|
367 | 368 | <p>Hello world! Object: NilClass, Arguments: bar and no block of text.</p> |
|
368 | 369 | EXPECTED |
|
369 | 370 | |
|
370 | 371 | assert_equal expected.gsub(%r{[\r\n\t]}, ''), textilizable(text).gsub(%r{[\r\n\t]}, '') |
|
371 | 372 | end |
|
372 | 373 | |
|
373 | 374 | def test_macros_should_be_escaped_in_pre_tags |
|
374 | 375 | text = "<pre>{{hello_world(<tag>)}}</pre>" |
|
375 | 376 | assert_equal "<pre>{{hello_world(<tag>)}}</pre>", textilizable(text) |
|
376 | 377 | end |
|
377 | 378 | |
|
378 | 379 | def test_macros_should_not_mangle_next_macros_outputs |
|
379 | 380 | text = '{{macro(2)}} !{{macro(2)}} {{hello_world(foo)}}' |
|
380 | 381 | assert_equal '<p>{{macro(2)}} {{macro(2)}} Hello world! Object: NilClass, Arguments: foo and no block of text.</p>', textilizable(text) |
|
381 | 382 | end |
|
382 | 383 | |
|
383 | 384 | def test_macros_with_text_should_not_mangle_following_macros |
|
384 | 385 | text = <<-RAW |
|
385 | 386 | {{hello_world |
|
386 | 387 | Line of text |
|
387 | 388 | }} |
|
388 | 389 | |
|
389 | 390 | {{hello_world |
|
390 | 391 | Another line of text |
|
391 | 392 | }} |
|
392 | 393 | RAW |
|
393 | 394 | |
|
394 | 395 | expected = <<-EXPECTED |
|
395 | 396 | <p>Hello world! Object: NilClass, Called with no argument and a 12 bytes long block of text.</p> |
|
396 | 397 | <p>Hello world! Object: NilClass, Called with no argument and a 20 bytes long block of text.</p> |
|
397 | 398 | EXPECTED |
|
398 | 399 | |
|
399 | 400 | assert_equal expected.gsub(%r{[\r\n\t]}, ''), textilizable(text).gsub(%r{[\r\n\t]}, '') |
|
400 | 401 | end |
|
401 | 402 | end |
General Comments 0
You need to be logged in to leave comments.
Login now