##// END OF EJS Templates
Reset current user before helpers tests....
Jean-Philippe Lang -
r15849:9d747d6811ed
parent child
Show More
@@ -1,401 +1,404
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2016 Jean-Philippe Lang
2 # Copyright (C) 2006-2016 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 if ENV["COVERAGE"]
18 if ENV["COVERAGE"]
19 require 'simplecov'
19 require 'simplecov'
20 require File.expand_path(File.dirname(__FILE__) + "/coverage/html_formatter")
20 require File.expand_path(File.dirname(__FILE__) + "/coverage/html_formatter")
21 SimpleCov.formatter = Redmine::Coverage::HtmlFormatter
21 SimpleCov.formatter = Redmine::Coverage::HtmlFormatter
22 SimpleCov.start 'rails'
22 SimpleCov.start 'rails'
23 end
23 end
24
24
25 $redmine_test_ldap_server = ENV['REDMINE_TEST_LDAP_SERVER'] || '127.0.0.1'
25 $redmine_test_ldap_server = ENV['REDMINE_TEST_LDAP_SERVER'] || '127.0.0.1'
26
26
27 ENV["RAILS_ENV"] = "test"
27 ENV["RAILS_ENV"] = "test"
28 require File.expand_path(File.dirname(__FILE__) + "/../config/environment")
28 require File.expand_path(File.dirname(__FILE__) + "/../config/environment")
29 require 'rails/test_help'
29 require 'rails/test_help'
30 require Rails.root.join('test', 'mocks', 'open_id_authentication_mock.rb').to_s
30 require Rails.root.join('test', 'mocks', 'open_id_authentication_mock.rb').to_s
31
31
32 require File.expand_path(File.dirname(__FILE__) + '/object_helpers')
32 require File.expand_path(File.dirname(__FILE__) + '/object_helpers')
33 include ObjectHelpers
33 include ObjectHelpers
34
34
35 require 'net/ldap'
35 require 'net/ldap'
36 require 'mocha/setup'
36 require 'mocha/setup'
37
37
38 Redmine::SudoMode.disable!
38 Redmine::SudoMode.disable!
39
39
40 class ActionView::TestCase
40 class ActionView::TestCase
41 helper :application
41 helper :application
42 include ApplicationHelper
42 include ApplicationHelper
43 end
43 end
44
44
45 class ActiveSupport::TestCase
45 class ActiveSupport::TestCase
46 include ActionDispatch::TestProcess
46 include ActionDispatch::TestProcess
47
47
48 self.use_transactional_fixtures = true
48 self.use_transactional_fixtures = true
49 self.use_instantiated_fixtures = false
49 self.use_instantiated_fixtures = false
50
50
51 def uploaded_test_file(name, mime)
51 def uploaded_test_file(name, mime)
52 fixture_file_upload("files/#{name}", mime, true)
52 fixture_file_upload("files/#{name}", mime, true)
53 end
53 end
54
54
55 # Mock out a file
55 # Mock out a file
56 def self.mock_file
56 def self.mock_file
57 file = 'a_file.png'
57 file = 'a_file.png'
58 file.stubs(:size).returns(32)
58 file.stubs(:size).returns(32)
59 file.stubs(:original_filename).returns('a_file.png')
59 file.stubs(:original_filename).returns('a_file.png')
60 file.stubs(:content_type).returns('image/png')
60 file.stubs(:content_type).returns('image/png')
61 file.stubs(:read).returns(false)
61 file.stubs(:read).returns(false)
62 file
62 file
63 end
63 end
64
64
65 def mock_file
65 def mock_file
66 self.class.mock_file
66 self.class.mock_file
67 end
67 end
68
68
69 def mock_file_with_options(options={})
69 def mock_file_with_options(options={})
70 file = ''
70 file = ''
71 file.stubs(:size).returns(32)
71 file.stubs(:size).returns(32)
72 original_filename = options[:original_filename] || nil
72 original_filename = options[:original_filename] || nil
73 file.stubs(:original_filename).returns(original_filename)
73 file.stubs(:original_filename).returns(original_filename)
74 content_type = options[:content_type] || nil
74 content_type = options[:content_type] || nil
75 file.stubs(:content_type).returns(content_type)
75 file.stubs(:content_type).returns(content_type)
76 file.stubs(:read).returns(false)
76 file.stubs(:read).returns(false)
77 file
77 file
78 end
78 end
79
79
80 # Use a temporary directory for attachment related tests
80 # Use a temporary directory for attachment related tests
81 def set_tmp_attachments_directory
81 def set_tmp_attachments_directory
82 Dir.mkdir "#{Rails.root}/tmp/test" unless File.directory?("#{Rails.root}/tmp/test")
82 Dir.mkdir "#{Rails.root}/tmp/test" unless File.directory?("#{Rails.root}/tmp/test")
83 unless File.directory?("#{Rails.root}/tmp/test/attachments")
83 unless File.directory?("#{Rails.root}/tmp/test/attachments")
84 Dir.mkdir "#{Rails.root}/tmp/test/attachments"
84 Dir.mkdir "#{Rails.root}/tmp/test/attachments"
85 end
85 end
86 Attachment.storage_path = "#{Rails.root}/tmp/test/attachments"
86 Attachment.storage_path = "#{Rails.root}/tmp/test/attachments"
87 end
87 end
88
88
89 def set_fixtures_attachments_directory
89 def set_fixtures_attachments_directory
90 Attachment.storage_path = "#{Rails.root}/test/fixtures/files"
90 Attachment.storage_path = "#{Rails.root}/test/fixtures/files"
91 end
91 end
92
92
93 def with_settings(options, &block)
93 def with_settings(options, &block)
94 saved_settings = options.keys.inject({}) do |h, k|
94 saved_settings = options.keys.inject({}) do |h, k|
95 h[k] = case Setting[k]
95 h[k] = case Setting[k]
96 when Symbol, false, true, nil
96 when Symbol, false, true, nil
97 Setting[k]
97 Setting[k]
98 else
98 else
99 Setting[k].dup
99 Setting[k].dup
100 end
100 end
101 h
101 h
102 end
102 end
103 options.each {|k, v| Setting[k] = v}
103 options.each {|k, v| Setting[k] = v}
104 yield
104 yield
105 ensure
105 ensure
106 saved_settings.each {|k, v| Setting[k] = v} if saved_settings
106 saved_settings.each {|k, v| Setting[k] = v} if saved_settings
107 end
107 end
108
108
109 # Yields the block with user as the current user
109 # Yields the block with user as the current user
110 def with_current_user(user, &block)
110 def with_current_user(user, &block)
111 saved_user = User.current
111 saved_user = User.current
112 User.current = user
112 User.current = user
113 yield
113 yield
114 ensure
114 ensure
115 User.current = saved_user
115 User.current = saved_user
116 end
116 end
117
117
118 def with_locale(locale, &block)
118 def with_locale(locale, &block)
119 saved_localed = ::I18n.locale
119 saved_localed = ::I18n.locale
120 ::I18n.locale = locale
120 ::I18n.locale = locale
121 yield
121 yield
122 ensure
122 ensure
123 ::I18n.locale = saved_localed
123 ::I18n.locale = saved_localed
124 end
124 end
125
125
126 def self.ldap_configured?
126 def self.ldap_configured?
127 @test_ldap = Net::LDAP.new(:host => $redmine_test_ldap_server, :port => 389)
127 @test_ldap = Net::LDAP.new(:host => $redmine_test_ldap_server, :port => 389)
128 return @test_ldap.bind
128 return @test_ldap.bind
129 rescue Exception => e
129 rescue Exception => e
130 # LDAP is not listening
130 # LDAP is not listening
131 return nil
131 return nil
132 end
132 end
133
133
134 def self.convert_installed?
134 def self.convert_installed?
135 Redmine::Thumbnail.convert_available?
135 Redmine::Thumbnail.convert_available?
136 end
136 end
137
137
138 def convert_installed?
138 def convert_installed?
139 self.class.convert_installed?
139 self.class.convert_installed?
140 end
140 end
141
141
142 # Returns the path to the test +vendor+ repository
142 # Returns the path to the test +vendor+ repository
143 def self.repository_path(vendor)
143 def self.repository_path(vendor)
144 path = Rails.root.join("tmp/test/#{vendor.downcase}_repository").to_s
144 path = Rails.root.join("tmp/test/#{vendor.downcase}_repository").to_s
145 # Unlike ruby, JRuby returns Rails.root with backslashes under Windows
145 # Unlike ruby, JRuby returns Rails.root with backslashes under Windows
146 path.tr("\\", "/")
146 path.tr("\\", "/")
147 end
147 end
148
148
149 # Returns the url of the subversion test repository
149 # Returns the url of the subversion test repository
150 def self.subversion_repository_url
150 def self.subversion_repository_url
151 path = repository_path('subversion')
151 path = repository_path('subversion')
152 path = '/' + path unless path.starts_with?('/')
152 path = '/' + path unless path.starts_with?('/')
153 "file://#{path}"
153 "file://#{path}"
154 end
154 end
155
155
156 # Returns true if the +vendor+ test repository is configured
156 # Returns true if the +vendor+ test repository is configured
157 def self.repository_configured?(vendor)
157 def self.repository_configured?(vendor)
158 File.directory?(repository_path(vendor))
158 File.directory?(repository_path(vendor))
159 end
159 end
160
160
161 def repository_path_hash(arr)
161 def repository_path_hash(arr)
162 hs = {}
162 hs = {}
163 hs[:path] = arr.join("/")
163 hs[:path] = arr.join("/")
164 hs[:param] = arr.join("/")
164 hs[:param] = arr.join("/")
165 hs
165 hs
166 end
166 end
167
167
168 def sqlite?
168 def sqlite?
169 ActiveRecord::Base.connection.adapter_name =~ /sqlite/i
169 ActiveRecord::Base.connection.adapter_name =~ /sqlite/i
170 end
170 end
171
171
172 def mysql?
172 def mysql?
173 ActiveRecord::Base.connection.adapter_name =~ /mysql/i
173 ActiveRecord::Base.connection.adapter_name =~ /mysql/i
174 end
174 end
175
175
176 def postgresql?
176 def postgresql?
177 ActiveRecord::Base.connection.adapter_name =~ /postgresql/i
177 ActiveRecord::Base.connection.adapter_name =~ /postgresql/i
178 end
178 end
179
179
180 def quoted_date(date)
180 def quoted_date(date)
181 date = Date.parse(date) if date.is_a?(String)
181 date = Date.parse(date) if date.is_a?(String)
182 ActiveRecord::Base.connection.quoted_date(date)
182 ActiveRecord::Base.connection.quoted_date(date)
183 end
183 end
184
184
185 # Asserts that a new record for the given class is created
185 # Asserts that a new record for the given class is created
186 # and returns it
186 # and returns it
187 def new_record(klass, &block)
187 def new_record(klass, &block)
188 new_records(klass, 1, &block).first
188 new_records(klass, 1, &block).first
189 end
189 end
190
190
191 # Asserts that count new records for the given class are created
191 # Asserts that count new records for the given class are created
192 # and returns them as an array order by object id
192 # and returns them as an array order by object id
193 def new_records(klass, count, &block)
193 def new_records(klass, count, &block)
194 assert_difference "#{klass}.count", count do
194 assert_difference "#{klass}.count", count do
195 yield
195 yield
196 end
196 end
197 klass.order(:id => :desc).limit(count).to_a.reverse
197 klass.order(:id => :desc).limit(count).to_a.reverse
198 end
198 end
199
199
200 def assert_save(object)
200 def assert_save(object)
201 saved = object.save
201 saved = object.save
202 message = "#{object.class} could not be saved"
202 message = "#{object.class} could not be saved"
203 errors = object.errors.full_messages.map {|m| "- #{m}"}
203 errors = object.errors.full_messages.map {|m| "- #{m}"}
204 message << ":\n#{errors.join("\n")}" if errors.any?
204 message << ":\n#{errors.join("\n")}" if errors.any?
205 assert_equal true, saved, message
205 assert_equal true, saved, message
206 end
206 end
207
207
208 def assert_select_error(arg)
208 def assert_select_error(arg)
209 assert_select '#errorExplanation', :text => arg
209 assert_select '#errorExplanation', :text => arg
210 end
210 end
211
211
212 def assert_include(expected, s, message=nil)
212 def assert_include(expected, s, message=nil)
213 assert s.include?(expected), (message || "\"#{expected}\" not found in \"#{s}\"")
213 assert s.include?(expected), (message || "\"#{expected}\" not found in \"#{s}\"")
214 end
214 end
215
215
216 def assert_not_include(expected, s, message=nil)
216 def assert_not_include(expected, s, message=nil)
217 assert !s.include?(expected), (message || "\"#{expected}\" found in \"#{s}\"")
217 assert !s.include?(expected), (message || "\"#{expected}\" found in \"#{s}\"")
218 end
218 end
219
219
220 def assert_select_in(text, *args, &block)
220 def assert_select_in(text, *args, &block)
221 d = Nokogiri::HTML(CGI::unescapeHTML(String.new(text))).root
221 d = Nokogiri::HTML(CGI::unescapeHTML(String.new(text))).root
222 assert_select(d, *args, &block)
222 assert_select(d, *args, &block)
223 end
223 end
224
224
225 def assert_select_email(*args, &block)
225 def assert_select_email(*args, &block)
226 email = ActionMailer::Base.deliveries.last
226 email = ActionMailer::Base.deliveries.last
227 assert_not_nil email
227 assert_not_nil email
228 html_body = email.parts.detect {|part| part.content_type.include?('text/html')}.try(&:body)
228 html_body = email.parts.detect {|part| part.content_type.include?('text/html')}.try(&:body)
229 assert_not_nil html_body
229 assert_not_nil html_body
230 assert_select_in html_body.encoded, *args, &block
230 assert_select_in html_body.encoded, *args, &block
231 end
231 end
232
232
233 def assert_mail_body_match(expected, mail, message=nil)
233 def assert_mail_body_match(expected, mail, message=nil)
234 if expected.is_a?(String)
234 if expected.is_a?(String)
235 assert_include expected, mail_body(mail), message
235 assert_include expected, mail_body(mail), message
236 else
236 else
237 assert_match expected, mail_body(mail), message
237 assert_match expected, mail_body(mail), message
238 end
238 end
239 end
239 end
240
240
241 def assert_mail_body_no_match(expected, mail, message=nil)
241 def assert_mail_body_no_match(expected, mail, message=nil)
242 if expected.is_a?(String)
242 if expected.is_a?(String)
243 assert_not_include expected, mail_body(mail), message
243 assert_not_include expected, mail_body(mail), message
244 else
244 else
245 assert_no_match expected, mail_body(mail), message
245 assert_no_match expected, mail_body(mail), message
246 end
246 end
247 end
247 end
248
248
249 def mail_body(mail)
249 def mail_body(mail)
250 mail.parts.first.body.encoded
250 mail.parts.first.body.encoded
251 end
251 end
252
252
253 # Returns the lft value for a new root issue
253 # Returns the lft value for a new root issue
254 def new_issue_lft
254 def new_issue_lft
255 1
255 1
256 end
256 end
257 end
257 end
258
258
259 module Redmine
259 module Redmine
260 class RoutingTest < ActionDispatch::IntegrationTest
260 class RoutingTest < ActionDispatch::IntegrationTest
261 def should_route(arg)
261 def should_route(arg)
262 arg = arg.dup
262 arg = arg.dup
263 request = arg.keys.detect {|key| key.is_a?(String)}
263 request = arg.keys.detect {|key| key.is_a?(String)}
264 raise ArgumentError unless request
264 raise ArgumentError unless request
265 options = arg.slice!(request)
265 options = arg.slice!(request)
266
266
267 raise ArgumentError unless request =~ /\A(GET|POST|PUT|PATCH|DELETE)\s+(.+)\z/
267 raise ArgumentError unless request =~ /\A(GET|POST|PUT|PATCH|DELETE)\s+(.+)\z/
268 method, path = $1.downcase.to_sym, $2
268 method, path = $1.downcase.to_sym, $2
269
269
270 raise ArgumentError unless arg.values.first =~ /\A(.+)#(.+)\z/
270 raise ArgumentError unless arg.values.first =~ /\A(.+)#(.+)\z/
271 controller, action = $1, $2
271 controller, action = $1, $2
272
272
273 assert_routing(
273 assert_routing(
274 {:method => method, :path => path},
274 {:method => method, :path => path},
275 options.merge(:controller => controller, :action => action)
275 options.merge(:controller => controller, :action => action)
276 )
276 )
277 end
277 end
278 end
278 end
279
279
280 class HelperTest < ActionView::TestCase
280 class HelperTest < ActionView::TestCase
281
281 def setup
282 super
283 User.current = nil
284 end
282 end
285 end
283
286
284 class ControllerTest < ActionController::TestCase
287 class ControllerTest < ActionController::TestCase
285 # Returns the issues that are displayed in the list in the same order
288 # Returns the issues that are displayed in the list in the same order
286 def issues_in_list
289 def issues_in_list
287 ids = css_select('tr.issue td.id').map(&:text).map(&:to_i)
290 ids = css_select('tr.issue td.id').map(&:text).map(&:to_i)
288 Issue.where(:id => ids).sort_by {|issue| ids.index(issue.id)}
291 Issue.where(:id => ids).sort_by {|issue| ids.index(issue.id)}
289 end
292 end
290
293
291 # Return the columns that are displayed in the list
294 # Return the columns that are displayed in the list
292 def columns_in_issues_list
295 def columns_in_issues_list
293 css_select('table.issues thead th:not(.checkbox)').map(&:text)
296 css_select('table.issues thead th:not(.checkbox)').map(&:text)
294 end
297 end
295
298
296 # Verifies that the query filters match the expected filters
299 # Verifies that the query filters match the expected filters
297 def assert_query_filters(expected_filters)
300 def assert_query_filters(expected_filters)
298 response.body =~ /initFilters\(\);\s*((addFilter\(.+\);\s*)*)/
301 response.body =~ /initFilters\(\);\s*((addFilter\(.+\);\s*)*)/
299 filter_init = $1.to_s
302 filter_init = $1.to_s
300
303
301 expected_filters.each do |field, operator, values|
304 expected_filters.each do |field, operator, values|
302 s = "addFilter(#{field.to_json}, #{operator.to_json}, #{Array(values).to_json});"
305 s = "addFilter(#{field.to_json}, #{operator.to_json}, #{Array(values).to_json});"
303 assert_include s, filter_init
306 assert_include s, filter_init
304 end
307 end
305 assert_equal expected_filters.size, filter_init.scan("addFilter").size, "filters counts don't match"
308 assert_equal expected_filters.size, filter_init.scan("addFilter").size, "filters counts don't match"
306 end
309 end
307
310
308 def process(method, path, parameters={}, session={}, flash={})
311 def process(method, path, parameters={}, session={}, flash={})
309 if parameters.key?(:params) || parameters.key?(:session)
312 if parameters.key?(:params) || parameters.key?(:session)
310 raise ArgumentError if session.present?
313 raise ArgumentError if session.present?
311 super method, path, parameters[:params], parameters[:session], parameters.except(:params, :session)
314 super method, path, parameters[:params], parameters[:session], parameters.except(:params, :session)
312 else
315 else
313 super
316 super
314 end
317 end
315 end
318 end
316 end
319 end
317
320
318 class IntegrationTest < ActionDispatch::IntegrationTest
321 class IntegrationTest < ActionDispatch::IntegrationTest
319 def log_user(login, password)
322 def log_user(login, password)
320 User.anonymous
323 User.anonymous
321 get "/login"
324 get "/login"
322 assert_nil session[:user_id]
325 assert_nil session[:user_id]
323 assert_response :success
326 assert_response :success
324
327
325 post "/login", :username => login, :password => password
328 post "/login", :username => login, :password => password
326 assert_equal login, User.find(session[:user_id]).login
329 assert_equal login, User.find(session[:user_id]).login
327 end
330 end
328
331
329 def credentials(user, password=nil)
332 def credentials(user, password=nil)
330 {'HTTP_AUTHORIZATION' => ActionController::HttpAuthentication::Basic.encode_credentials(user, password || user)}
333 {'HTTP_AUTHORIZATION' => ActionController::HttpAuthentication::Basic.encode_credentials(user, password || user)}
331 end
334 end
332 end
335 end
333
336
334 module ApiTest
337 module ApiTest
335 API_FORMATS = %w(json xml).freeze
338 API_FORMATS = %w(json xml).freeze
336
339
337 # Base class for API tests
340 # Base class for API tests
338 class Base < Redmine::IntegrationTest
341 class Base < Redmine::IntegrationTest
339 def setup
342 def setup
340 Setting.rest_api_enabled = '1'
343 Setting.rest_api_enabled = '1'
341 end
344 end
342
345
343 def teardown
346 def teardown
344 Setting.rest_api_enabled = '0'
347 Setting.rest_api_enabled = '0'
345 end
348 end
346
349
347 # Uploads content using the XML API and returns the attachment token
350 # Uploads content using the XML API and returns the attachment token
348 def xml_upload(content, credentials)
351 def xml_upload(content, credentials)
349 upload('xml', content, credentials)
352 upload('xml', content, credentials)
350 end
353 end
351
354
352 # Uploads content using the JSON API and returns the attachment token
355 # Uploads content using the JSON API and returns the attachment token
353 def json_upload(content, credentials)
356 def json_upload(content, credentials)
354 upload('json', content, credentials)
357 upload('json', content, credentials)
355 end
358 end
356
359
357 def upload(format, content, credentials)
360 def upload(format, content, credentials)
358 set_tmp_attachments_directory
361 set_tmp_attachments_directory
359 assert_difference 'Attachment.count' do
362 assert_difference 'Attachment.count' do
360 post "/uploads.#{format}", content, {"CONTENT_TYPE" => 'application/octet-stream'}.merge(credentials)
363 post "/uploads.#{format}", content, {"CONTENT_TYPE" => 'application/octet-stream'}.merge(credentials)
361 assert_response :created
364 assert_response :created
362 end
365 end
363 data = response_data
366 data = response_data
364 assert_kind_of Hash, data['upload']
367 assert_kind_of Hash, data['upload']
365 token = data['upload']['token']
368 token = data['upload']['token']
366 assert_not_nil token
369 assert_not_nil token
367 token
370 token
368 end
371 end
369
372
370 # Parses the response body based on its content type
373 # Parses the response body based on its content type
371 def response_data
374 def response_data
372 unless response.content_type.to_s =~ /^application\/(.+)/
375 unless response.content_type.to_s =~ /^application\/(.+)/
373 raise "Unexpected response type: #{response.content_type}"
376 raise "Unexpected response type: #{response.content_type}"
374 end
377 end
375 format = $1
378 format = $1
376 case format
379 case format
377 when 'xml'
380 when 'xml'
378 Hash.from_xml(response.body)
381 Hash.from_xml(response.body)
379 when 'json'
382 when 'json'
380 ActiveSupport::JSON.decode(response.body)
383 ActiveSupport::JSON.decode(response.body)
381 else
384 else
382 raise "Unknown response format: #{format}"
385 raise "Unknown response format: #{format}"
383 end
386 end
384 end
387 end
385 end
388 end
386
389
387 class Routing < Redmine::RoutingTest
390 class Routing < Redmine::RoutingTest
388 def should_route(arg)
391 def should_route(arg)
389 arg = arg.dup
392 arg = arg.dup
390 request = arg.keys.detect {|key| key.is_a?(String)}
393 request = arg.keys.detect {|key| key.is_a?(String)}
391 raise ArgumentError unless request
394 raise ArgumentError unless request
392 options = arg.slice!(request)
395 options = arg.slice!(request)
393
396
394 API_FORMATS.each do |format|
397 API_FORMATS.each do |format|
395 format_request = request.sub /$/, ".#{format}"
398 format_request = request.sub /$/, ".#{format}"
396 super options.merge(format_request => arg[request], :format => format)
399 super options.merge(format_request => arg[request], :format => format)
397 end
400 end
398 end
401 end
399 end
402 end
400 end
403 end
401 end
404 end
@@ -1,102 +1,103
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2016 Jean-Philippe Lang
2 # Copyright (C) 2006-2016 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require File.expand_path('../../../test_helper', __FILE__)
18 require File.expand_path('../../../test_helper', __FILE__)
19
19
20 class ActivitiesHelperTest < Redmine::HelperTest
20 class ActivitiesHelperTest < Redmine::HelperTest
21 include ActivitiesHelper
21 include ActivitiesHelper
22 include Redmine::I18n
22 include Redmine::I18n
23
23
24 class MockEvent
24 class MockEvent
25 attr_reader :event_datetime, :event_group, :name
25 attr_reader :event_datetime, :event_group, :name
26
26
27 def initialize(group=nil)
27 def initialize(group=nil)
28 @@count ||= 0
28 @@count ||= 0
29 @name = "e#{@@count}"
29 @name = "e#{@@count}"
30 @event_datetime = Time.now + @@count.hours
30 @event_datetime = Time.now + @@count.hours
31 @event_group = group || self
31 @event_group = group || self
32 @@count += 1
32 @@count += 1
33 end
33 end
34
34
35 def self.clear
35 def self.clear
36 @@count = 0
36 @@count = 0
37 end
37 end
38 end
38 end
39
39
40 def setup
40 def setup
41 super
41 MockEvent.clear
42 MockEvent.clear
42 end
43 end
43
44
44 def test_sort_activity_events_should_sort_by_datetime
45 def test_sort_activity_events_should_sort_by_datetime
45 events = []
46 events = []
46 events << MockEvent.new
47 events << MockEvent.new
47 events << MockEvent.new
48 events << MockEvent.new
48 events << MockEvent.new
49 events << MockEvent.new
49
50
50 assert_equal [
51 assert_equal [
51 ['e2', false],
52 ['e2', false],
52 ['e1', false],
53 ['e1', false],
53 ['e0', false]
54 ['e0', false]
54 ], sort_activity_events(events).map {|event, grouped| [event.name, grouped]}
55 ], sort_activity_events(events).map {|event, grouped| [event.name, grouped]}
55 end
56 end
56
57
57 def test_sort_activity_events_should_group_events
58 def test_sort_activity_events_should_group_events
58 events = []
59 events = []
59 events << MockEvent.new
60 events << MockEvent.new
60 events << MockEvent.new(events[0])
61 events << MockEvent.new(events[0])
61 events << MockEvent.new(events[0])
62 events << MockEvent.new(events[0])
62
63
63 assert_equal [
64 assert_equal [
64 ['e2', false],
65 ['e2', false],
65 ['e1', true],
66 ['e1', true],
66 ['e0', true]
67 ['e0', true]
67 ], sort_activity_events(events).map {|event, grouped| [event.name, grouped]}
68 ], sort_activity_events(events).map {|event, grouped| [event.name, grouped]}
68 end
69 end
69
70
70 def test_sort_activity_events_with_group_not_in_set_should_group_events
71 def test_sort_activity_events_with_group_not_in_set_should_group_events
71 e = MockEvent.new
72 e = MockEvent.new
72 events = []
73 events = []
73 events << MockEvent.new(e)
74 events << MockEvent.new(e)
74 events << MockEvent.new(e)
75 events << MockEvent.new(e)
75
76
76 assert_equal [
77 assert_equal [
77 ['e2', false],
78 ['e2', false],
78 ['e1', true]
79 ['e1', true]
79 ], sort_activity_events(events).map {|event, grouped| [event.name, grouped]}
80 ], sort_activity_events(events).map {|event, grouped| [event.name, grouped]}
80 end
81 end
81
82
82 def test_sort_activity_events_should_sort_by_datetime_and_group
83 def test_sort_activity_events_should_sort_by_datetime_and_group
83 events = []
84 events = []
84 events << MockEvent.new
85 events << MockEvent.new
85 events << MockEvent.new
86 events << MockEvent.new
86 events << MockEvent.new
87 events << MockEvent.new
87 events << MockEvent.new(events[1])
88 events << MockEvent.new(events[1])
88 events << MockEvent.new(events[2])
89 events << MockEvent.new(events[2])
89 events << MockEvent.new
90 events << MockEvent.new
90 events << MockEvent.new(events[2])
91 events << MockEvent.new(events[2])
91
92
92 assert_equal [
93 assert_equal [
93 ['e6', false],
94 ['e6', false],
94 ['e4', true],
95 ['e4', true],
95 ['e2', true],
96 ['e2', true],
96 ['e5', false],
97 ['e5', false],
97 ['e3', false],
98 ['e3', false],
98 ['e1', true],
99 ['e1', true],
99 ['e0', false]
100 ['e0', false]
100 ], sort_activity_events(events).map {|event, grouped| [event.name, grouped]}
101 ], sort_activity_events(events).map {|event, grouped| [event.name, grouped]}
101 end
102 end
102 end
103 end
@@ -1,339 +1,338
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2016 Jean-Philippe Lang
2 # Copyright (C) 2006-2016 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require File.expand_path('../../../test_helper', __FILE__)
18 require File.expand_path('../../../test_helper', __FILE__)
19
19
20 class IssuesHelperTest < Redmine::HelperTest
20 class IssuesHelperTest < Redmine::HelperTest
21 include Redmine::I18n
21 include Redmine::I18n
22 include IssuesHelper
22 include IssuesHelper
23 include CustomFieldsHelper
23 include CustomFieldsHelper
24 include ERB::Util
24 include ERB::Util
25 include Rails.application.routes.url_helpers
25 include Rails.application.routes.url_helpers
26
26
27 fixtures :projects, :trackers, :issue_statuses, :issues,
27 fixtures :projects, :trackers, :issue_statuses, :issues,
28 :enumerations, :users, :issue_categories,
28 :enumerations, :users, :issue_categories,
29 :projects_trackers,
29 :projects_trackers,
30 :roles,
30 :roles,
31 :member_roles,
31 :member_roles,
32 :members,
32 :members,
33 :enabled_modules,
33 :enabled_modules,
34 :custom_fields,
34 :custom_fields,
35 :attachments,
35 :attachments,
36 :versions
36 :versions
37
37
38 def setup
38 def setup
39 super
39 super
40 set_language_if_valid('en')
40 set_language_if_valid('en')
41 User.current = nil
42 end
41 end
43
42
44 def test_issue_heading
43 def test_issue_heading
45 assert_equal "Bug #1", issue_heading(Issue.find(1))
44 assert_equal "Bug #1", issue_heading(Issue.find(1))
46 end
45 end
47
46
48 def test_issues_destroy_confirmation_message_with_one_root_issue
47 def test_issues_destroy_confirmation_message_with_one_root_issue
49 assert_equal l(:text_issues_destroy_confirmation),
48 assert_equal l(:text_issues_destroy_confirmation),
50 issues_destroy_confirmation_message(Issue.find(1))
49 issues_destroy_confirmation_message(Issue.find(1))
51 end
50 end
52
51
53 def test_issues_destroy_confirmation_message_with_an_arrayt_of_root_issues
52 def test_issues_destroy_confirmation_message_with_an_arrayt_of_root_issues
54 assert_equal l(:text_issues_destroy_confirmation),
53 assert_equal l(:text_issues_destroy_confirmation),
55 issues_destroy_confirmation_message(Issue.find([1, 2]))
54 issues_destroy_confirmation_message(Issue.find([1, 2]))
56 end
55 end
57
56
58 def test_issues_destroy_confirmation_message_with_one_parent_issue
57 def test_issues_destroy_confirmation_message_with_one_parent_issue
59 Issue.find(2).update! :parent_issue_id => 1
58 Issue.find(2).update! :parent_issue_id => 1
60 assert_equal l(:text_issues_destroy_confirmation) + "\n" +
59 assert_equal l(:text_issues_destroy_confirmation) + "\n" +
61 l(:text_issues_destroy_descendants_confirmation, :count => 1),
60 l(:text_issues_destroy_descendants_confirmation, :count => 1),
62 issues_destroy_confirmation_message(Issue.find(1))
61 issues_destroy_confirmation_message(Issue.find(1))
63 end
62 end
64
63
65 def test_issues_destroy_confirmation_message_with_one_parent_issue_and_its_child
64 def test_issues_destroy_confirmation_message_with_one_parent_issue_and_its_child
66 Issue.find(2).update! :parent_issue_id => 1
65 Issue.find(2).update! :parent_issue_id => 1
67 assert_equal l(:text_issues_destroy_confirmation),
66 assert_equal l(:text_issues_destroy_confirmation),
68 issues_destroy_confirmation_message(Issue.find([1, 2]))
67 issues_destroy_confirmation_message(Issue.find([1, 2]))
69 end
68 end
70
69
71 def test_issues_destroy_confirmation_message_with_issues_that_share_descendants
70 def test_issues_destroy_confirmation_message_with_issues_that_share_descendants
72 root = Issue.generate!
71 root = Issue.generate!
73 child = Issue.generate!(:parent_issue_id => root.id)
72 child = Issue.generate!(:parent_issue_id => root.id)
74 Issue.generate!(:parent_issue_id => child.id)
73 Issue.generate!(:parent_issue_id => child.id)
75
74
76 assert_equal l(:text_issues_destroy_confirmation) + "\n" +
75 assert_equal l(:text_issues_destroy_confirmation) + "\n" +
77 l(:text_issues_destroy_descendants_confirmation, :count => 1),
76 l(:text_issues_destroy_descendants_confirmation, :count => 1),
78 issues_destroy_confirmation_message([root.reload, child.reload])
77 issues_destroy_confirmation_message([root.reload, child.reload])
79 end
78 end
80
79
81 test 'show_detail with no_html should show a changing attribute' do
80 test 'show_detail with no_html should show a changing attribute' do
82 detail = JournalDetail.new(:property => 'attr', :old_value => '40',
81 detail = JournalDetail.new(:property => 'attr', :old_value => '40',
83 :value => '100', :prop_key => 'done_ratio')
82 :value => '100', :prop_key => 'done_ratio')
84 assert_equal "% Done changed from 40 to 100", show_detail(detail, true)
83 assert_equal "% Done changed from 40 to 100", show_detail(detail, true)
85 end
84 end
86
85
87 test 'show_detail with no_html should show a new attribute' do
86 test 'show_detail with no_html should show a new attribute' do
88 detail = JournalDetail.new(:property => 'attr', :old_value => nil,
87 detail = JournalDetail.new(:property => 'attr', :old_value => nil,
89 :value => '100', :prop_key => 'done_ratio')
88 :value => '100', :prop_key => 'done_ratio')
90 assert_equal "% Done set to 100", show_detail(detail, true)
89 assert_equal "% Done set to 100", show_detail(detail, true)
91 end
90 end
92
91
93 test 'show_detail with no_html should show a deleted attribute' do
92 test 'show_detail with no_html should show a deleted attribute' do
94 detail = JournalDetail.new(:property => 'attr', :old_value => '50',
93 detail = JournalDetail.new(:property => 'attr', :old_value => '50',
95 :value => nil, :prop_key => 'done_ratio')
94 :value => nil, :prop_key => 'done_ratio')
96 assert_equal "% Done deleted (50)", show_detail(detail, true)
95 assert_equal "% Done deleted (50)", show_detail(detail, true)
97 end
96 end
98
97
99 test 'show_detail with html should show a changing attribute with HTML highlights' do
98 test 'show_detail with html should show a changing attribute with HTML highlights' do
100 detail = JournalDetail.new(:property => 'attr', :old_value => '40',
99 detail = JournalDetail.new(:property => 'attr', :old_value => '40',
101 :value => '100', :prop_key => 'done_ratio')
100 :value => '100', :prop_key => 'done_ratio')
102 html = show_detail(detail, false)
101 html = show_detail(detail, false)
103 assert_include '<strong>% Done</strong>', html
102 assert_include '<strong>% Done</strong>', html
104 assert_include '<i>40</i>', html
103 assert_include '<i>40</i>', html
105 assert_include '<i>100</i>', html
104 assert_include '<i>100</i>', html
106 end
105 end
107
106
108 test 'show_detail with html should show a new attribute with HTML highlights' do
107 test 'show_detail with html should show a new attribute with HTML highlights' do
109 detail = JournalDetail.new(:property => 'attr', :old_value => nil,
108 detail = JournalDetail.new(:property => 'attr', :old_value => nil,
110 :value => '100', :prop_key => 'done_ratio')
109 :value => '100', :prop_key => 'done_ratio')
111 html = show_detail(detail, false)
110 html = show_detail(detail, false)
112 assert_include '<strong>% Done</strong>', html
111 assert_include '<strong>% Done</strong>', html
113 assert_include '<i>100</i>', html
112 assert_include '<i>100</i>', html
114 end
113 end
115
114
116 test 'show_detail with html should show a deleted attribute with HTML highlights' do
115 test 'show_detail with html should show a deleted attribute with HTML highlights' do
117 detail = JournalDetail.new(:property => 'attr', :old_value => '50',
116 detail = JournalDetail.new(:property => 'attr', :old_value => '50',
118 :value => nil, :prop_key => 'done_ratio')
117 :value => nil, :prop_key => 'done_ratio')
119 html = show_detail(detail, false)
118 html = show_detail(detail, false)
120 assert_include '<strong>% Done</strong>', html
119 assert_include '<strong>% Done</strong>', html
121 assert_include '<del><i>50</i></del>', html
120 assert_include '<del><i>50</i></del>', html
122 end
121 end
123
122
124 test 'show_detail with a start_date attribute should format the dates' do
123 test 'show_detail with a start_date attribute should format the dates' do
125 detail = JournalDetail.new(
124 detail = JournalDetail.new(
126 :property => 'attr',
125 :property => 'attr',
127 :old_value => '2010-01-01',
126 :old_value => '2010-01-01',
128 :value => '2010-01-31',
127 :value => '2010-01-31',
129 :prop_key => 'start_date'
128 :prop_key => 'start_date'
130 )
129 )
131 with_settings :date_format => '%m/%d/%Y' do
130 with_settings :date_format => '%m/%d/%Y' do
132 assert_match "01/31/2010", show_detail(detail, true)
131 assert_match "01/31/2010", show_detail(detail, true)
133 assert_match "01/01/2010", show_detail(detail, true)
132 assert_match "01/01/2010", show_detail(detail, true)
134 end
133 end
135 end
134 end
136
135
137 test 'show_detail with a due_date attribute should format the dates' do
136 test 'show_detail with a due_date attribute should format the dates' do
138 detail = JournalDetail.new(
137 detail = JournalDetail.new(
139 :property => 'attr',
138 :property => 'attr',
140 :old_value => '2010-01-01',
139 :old_value => '2010-01-01',
141 :value => '2010-01-31',
140 :value => '2010-01-31',
142 :prop_key => 'due_date'
141 :prop_key => 'due_date'
143 )
142 )
144 with_settings :date_format => '%m/%d/%Y' do
143 with_settings :date_format => '%m/%d/%Y' do
145 assert_match "01/31/2010", show_detail(detail, true)
144 assert_match "01/31/2010", show_detail(detail, true)
146 assert_match "01/01/2010", show_detail(detail, true)
145 assert_match "01/01/2010", show_detail(detail, true)
147 end
146 end
148 end
147 end
149
148
150 test 'show_detail should show old and new values with a project attribute' do
149 test 'show_detail should show old and new values with a project attribute' do
151 detail = JournalDetail.new(:property => 'attr', :prop_key => 'project_id',
150 detail = JournalDetail.new(:property => 'attr', :prop_key => 'project_id',
152 :old_value => 1, :value => 2)
151 :old_value => 1, :value => 2)
153 assert_match 'eCookbook', show_detail(detail, true)
152 assert_match 'eCookbook', show_detail(detail, true)
154 assert_match 'OnlineStore', show_detail(detail, true)
153 assert_match 'OnlineStore', show_detail(detail, true)
155 end
154 end
156
155
157 test 'show_detail should show old and new values with a issue status attribute' do
156 test 'show_detail should show old and new values with a issue status attribute' do
158 detail = JournalDetail.new(:property => 'attr', :prop_key => 'status_id',
157 detail = JournalDetail.new(:property => 'attr', :prop_key => 'status_id',
159 :old_value => 1, :value => 2)
158 :old_value => 1, :value => 2)
160 assert_match 'New', show_detail(detail, true)
159 assert_match 'New', show_detail(detail, true)
161 assert_match 'Assigned', show_detail(detail, true)
160 assert_match 'Assigned', show_detail(detail, true)
162 end
161 end
163
162
164 test 'show_detail should show old and new values with a tracker attribute' do
163 test 'show_detail should show old and new values with a tracker attribute' do
165 detail = JournalDetail.new(:property => 'attr', :prop_key => 'tracker_id',
164 detail = JournalDetail.new(:property => 'attr', :prop_key => 'tracker_id',
166 :old_value => 1, :value => 2)
165 :old_value => 1, :value => 2)
167 assert_match 'Bug', show_detail(detail, true)
166 assert_match 'Bug', show_detail(detail, true)
168 assert_match 'Feature request', show_detail(detail, true)
167 assert_match 'Feature request', show_detail(detail, true)
169 end
168 end
170
169
171 test 'show_detail should show old and new values with a assigned to attribute' do
170 test 'show_detail should show old and new values with a assigned to attribute' do
172 detail = JournalDetail.new(:property => 'attr', :prop_key => 'assigned_to_id',
171 detail = JournalDetail.new(:property => 'attr', :prop_key => 'assigned_to_id',
173 :old_value => 1, :value => 2)
172 :old_value => 1, :value => 2)
174 assert_match 'Redmine Admin', show_detail(detail, true)
173 assert_match 'Redmine Admin', show_detail(detail, true)
175 assert_match 'John Smith', show_detail(detail, true)
174 assert_match 'John Smith', show_detail(detail, true)
176 end
175 end
177
176
178 test 'show_detail should show old and new values with a priority attribute' do
177 test 'show_detail should show old and new values with a priority attribute' do
179 detail = JournalDetail.new(:property => 'attr', :prop_key => 'priority_id',
178 detail = JournalDetail.new(:property => 'attr', :prop_key => 'priority_id',
180 :old_value => 4, :value => 5)
179 :old_value => 4, :value => 5)
181 assert_match 'Low', show_detail(detail, true)
180 assert_match 'Low', show_detail(detail, true)
182 assert_match 'Normal', show_detail(detail, true)
181 assert_match 'Normal', show_detail(detail, true)
183 end
182 end
184
183
185 test 'show_detail should show old and new values with a category attribute' do
184 test 'show_detail should show old and new values with a category attribute' do
186 detail = JournalDetail.new(:property => 'attr', :prop_key => 'category_id',
185 detail = JournalDetail.new(:property => 'attr', :prop_key => 'category_id',
187 :old_value => 1, :value => 2)
186 :old_value => 1, :value => 2)
188 assert_match 'Printing', show_detail(detail, true)
187 assert_match 'Printing', show_detail(detail, true)
189 assert_match 'Recipes', show_detail(detail, true)
188 assert_match 'Recipes', show_detail(detail, true)
190 end
189 end
191
190
192 test 'show_detail should show old and new values with a fixed version attribute' do
191 test 'show_detail should show old and new values with a fixed version attribute' do
193 detail = JournalDetail.new(:property => 'attr', :prop_key => 'fixed_version_id',
192 detail = JournalDetail.new(:property => 'attr', :prop_key => 'fixed_version_id',
194 :old_value => 1, :value => 2)
193 :old_value => 1, :value => 2)
195 assert_match '0.1', show_detail(detail, true)
194 assert_match '0.1', show_detail(detail, true)
196 assert_match '1.0', show_detail(detail, true)
195 assert_match '1.0', show_detail(detail, true)
197 end
196 end
198
197
199 test 'show_detail should show old and new values with a estimated hours attribute' do
198 test 'show_detail should show old and new values with a estimated hours attribute' do
200 detail = JournalDetail.new(:property => 'attr', :prop_key => 'estimated_hours',
199 detail = JournalDetail.new(:property => 'attr', :prop_key => 'estimated_hours',
201 :old_value => '5', :value => '6.3')
200 :old_value => '5', :value => '6.3')
202 assert_match '5.00', show_detail(detail, true)
201 assert_match '5.00', show_detail(detail, true)
203 assert_match '6.30', show_detail(detail, true)
202 assert_match '6.30', show_detail(detail, true)
204 end
203 end
205
204
206 test 'show_detail should not show values with a description attribute' do
205 test 'show_detail should not show values with a description attribute' do
207 detail = JournalDetail.new(:property => 'attr', :prop_key => 'description',
206 detail = JournalDetail.new(:property => 'attr', :prop_key => 'description',
208 :old_value => 'Foo', :value => 'Bar')
207 :old_value => 'Foo', :value => 'Bar')
209 assert_equal 'Description updated', show_detail(detail, true)
208 assert_equal 'Description updated', show_detail(detail, true)
210 end
209 end
211
210
212 test 'show_detail should show old and new values with a custom field' do
211 test 'show_detail should show old and new values with a custom field' do
213 detail = JournalDetail.new(:property => 'cf', :prop_key => '1',
212 detail = JournalDetail.new(:property => 'cf', :prop_key => '1',
214 :old_value => 'MySQL', :value => 'PostgreSQL')
213 :old_value => 'MySQL', :value => 'PostgreSQL')
215 assert_equal 'Database changed from MySQL to PostgreSQL', show_detail(detail, true)
214 assert_equal 'Database changed from MySQL to PostgreSQL', show_detail(detail, true)
216 end
215 end
217
216
218 test 'show_detail should not show values with a long text custom field' do
217 test 'show_detail should not show values with a long text custom field' do
219 field = IssueCustomField.create!(:name => "Long field", :field_format => 'text')
218 field = IssueCustomField.create!(:name => "Long field", :field_format => 'text')
220 detail = JournalDetail.new(:property => 'cf', :prop_key => field.id,
219 detail = JournalDetail.new(:property => 'cf', :prop_key => field.id,
221 :old_value => 'Foo', :value => 'Bar')
220 :old_value => 'Foo', :value => 'Bar')
222 assert_equal 'Long field updated', show_detail(detail, true)
221 assert_equal 'Long field updated', show_detail(detail, true)
223 end
222 end
224
223
225 test 'show_detail should show added file' do
224 test 'show_detail should show added file' do
226 detail = JournalDetail.new(:property => 'attachment', :prop_key => '1',
225 detail = JournalDetail.new(:property => 'attachment', :prop_key => '1',
227 :old_value => nil, :value => 'error281.txt')
226 :old_value => nil, :value => 'error281.txt')
228 assert_match 'error281.txt', show_detail(detail, true)
227 assert_match 'error281.txt', show_detail(detail, true)
229 end
228 end
230
229
231 test 'show_detail should show removed file' do
230 test 'show_detail should show removed file' do
232 detail = JournalDetail.new(:property => 'attachment', :prop_key => '1',
231 detail = JournalDetail.new(:property => 'attachment', :prop_key => '1',
233 :old_value => 'error281.txt', :value => nil)
232 :old_value => 'error281.txt', :value => nil)
234 assert_match 'error281.txt', show_detail(detail, true)
233 assert_match 'error281.txt', show_detail(detail, true)
235 end
234 end
236
235
237 def test_show_detail_relation_added
236 def test_show_detail_relation_added
238 detail = JournalDetail.new(:property => 'relation',
237 detail = JournalDetail.new(:property => 'relation',
239 :prop_key => 'precedes',
238 :prop_key => 'precedes',
240 :value => 1)
239 :value => 1)
241 assert_equal "Precedes Bug #1: Cannot print recipes added", show_detail(detail, true)
240 assert_equal "Precedes Bug #1: Cannot print recipes added", show_detail(detail, true)
242 str = link_to("Bug #1", "/issues/1", :class => Issue.find(1).css_classes)
241 str = link_to("Bug #1", "/issues/1", :class => Issue.find(1).css_classes)
243 assert_equal "<strong>Precedes</strong> <i>#{str}: Cannot print recipes</i> added",
242 assert_equal "<strong>Precedes</strong> <i>#{str}: Cannot print recipes</i> added",
244 show_detail(detail, false)
243 show_detail(detail, false)
245 end
244 end
246
245
247 def test_show_detail_relation_added_with_inexistant_issue
246 def test_show_detail_relation_added_with_inexistant_issue
248 inexistant_issue_number = 9999
247 inexistant_issue_number = 9999
249 assert_nil Issue.find_by_id(inexistant_issue_number)
248 assert_nil Issue.find_by_id(inexistant_issue_number)
250 detail = JournalDetail.new(:property => 'relation',
249 detail = JournalDetail.new(:property => 'relation',
251 :prop_key => 'precedes',
250 :prop_key => 'precedes',
252 :value => inexistant_issue_number)
251 :value => inexistant_issue_number)
253 assert_equal "Precedes Issue ##{inexistant_issue_number} added", show_detail(detail, true)
252 assert_equal "Precedes Issue ##{inexistant_issue_number} added", show_detail(detail, true)
254 assert_equal "<strong>Precedes</strong> <i>Issue ##{inexistant_issue_number}</i> added", show_detail(detail, false)
253 assert_equal "<strong>Precedes</strong> <i>Issue ##{inexistant_issue_number}</i> added", show_detail(detail, false)
255 end
254 end
256
255
257 def test_show_detail_relation_added_should_not_disclose_issue_that_is_not_visible
256 def test_show_detail_relation_added_should_not_disclose_issue_that_is_not_visible
258 issue = Issue.generate!(:is_private => true)
257 issue = Issue.generate!(:is_private => true)
259 detail = JournalDetail.new(:property => 'relation',
258 detail = JournalDetail.new(:property => 'relation',
260 :prop_key => 'precedes',
259 :prop_key => 'precedes',
261 :value => issue.id)
260 :value => issue.id)
262
261
263 assert_equal "Precedes Issue ##{issue.id} added", show_detail(detail, true)
262 assert_equal "Precedes Issue ##{issue.id} added", show_detail(detail, true)
264 assert_equal "<strong>Precedes</strong> <i>Issue ##{issue.id}</i> added", show_detail(detail, false)
263 assert_equal "<strong>Precedes</strong> <i>Issue ##{issue.id}</i> added", show_detail(detail, false)
265 end
264 end
266
265
267 def test_show_detail_relation_deleted
266 def test_show_detail_relation_deleted
268 detail = JournalDetail.new(:property => 'relation',
267 detail = JournalDetail.new(:property => 'relation',
269 :prop_key => 'precedes',
268 :prop_key => 'precedes',
270 :old_value => 1)
269 :old_value => 1)
271 assert_equal "Precedes deleted (Bug #1: Cannot print recipes)", show_detail(detail, true)
270 assert_equal "Precedes deleted (Bug #1: Cannot print recipes)", show_detail(detail, true)
272 str = link_to("Bug #1",
271 str = link_to("Bug #1",
273 "/issues/1",
272 "/issues/1",
274 :class => Issue.find(1).css_classes)
273 :class => Issue.find(1).css_classes)
275 assert_equal "<strong>Precedes</strong> deleted (<i>#{str}: Cannot print recipes</i>)",
274 assert_equal "<strong>Precedes</strong> deleted (<i>#{str}: Cannot print recipes</i>)",
276 show_detail(detail, false)
275 show_detail(detail, false)
277 end
276 end
278
277
279 def test_show_detail_relation_deleted_with_inexistant_issue
278 def test_show_detail_relation_deleted_with_inexistant_issue
280 inexistant_issue_number = 9999
279 inexistant_issue_number = 9999
281 assert_nil Issue.find_by_id(inexistant_issue_number)
280 assert_nil Issue.find_by_id(inexistant_issue_number)
282 detail = JournalDetail.new(:property => 'relation',
281 detail = JournalDetail.new(:property => 'relation',
283 :prop_key => 'precedes',
282 :prop_key => 'precedes',
284 :old_value => inexistant_issue_number)
283 :old_value => inexistant_issue_number)
285 assert_equal "Precedes deleted (Issue #9999)", show_detail(detail, true)
284 assert_equal "Precedes deleted (Issue #9999)", show_detail(detail, true)
286 assert_equal "<strong>Precedes</strong> deleted (<i>Issue #9999</i>)", show_detail(detail, false)
285 assert_equal "<strong>Precedes</strong> deleted (<i>Issue #9999</i>)", show_detail(detail, false)
287 end
286 end
288
287
289 def test_show_detail_relation_deleted_should_not_disclose_issue_that_is_not_visible
288 def test_show_detail_relation_deleted_should_not_disclose_issue_that_is_not_visible
290 issue = Issue.generate!(:is_private => true)
289 issue = Issue.generate!(:is_private => true)
291 detail = JournalDetail.new(:property => 'relation',
290 detail = JournalDetail.new(:property => 'relation',
292 :prop_key => 'precedes',
291 :prop_key => 'precedes',
293 :old_value => issue.id)
292 :old_value => issue.id)
294
293
295 assert_equal "Precedes deleted (Issue ##{issue.id})", show_detail(detail, true)
294 assert_equal "Precedes deleted (Issue ##{issue.id})", show_detail(detail, true)
296 assert_equal "<strong>Precedes</strong> deleted (<i>Issue ##{issue.id}</i>)", show_detail(detail, false)
295 assert_equal "<strong>Precedes</strong> deleted (<i>Issue ##{issue.id}</i>)", show_detail(detail, false)
297 end
296 end
298
297
299 def test_details_to_strings_with_multiple_values_removed_from_custom_field
298 def test_details_to_strings_with_multiple_values_removed_from_custom_field
300 field = IssueCustomField.generate!(:name => 'User', :field_format => 'user', :multiple => true)
299 field = IssueCustomField.generate!(:name => 'User', :field_format => 'user', :multiple => true)
301 details = []
300 details = []
302 details << JournalDetail.new(:property => 'cf', :prop_key => field.id.to_s, :old_value => '1', :value => nil)
301 details << JournalDetail.new(:property => 'cf', :prop_key => field.id.to_s, :old_value => '1', :value => nil)
303 details << JournalDetail.new(:property => 'cf', :prop_key => field.id.to_s, :old_value => '3', :value => nil)
302 details << JournalDetail.new(:property => 'cf', :prop_key => field.id.to_s, :old_value => '3', :value => nil)
304
303
305 assert_equal ["User deleted (Dave Lopper, Redmine Admin)"], details_to_strings(details, true)
304 assert_equal ["User deleted (Dave Lopper, Redmine Admin)"], details_to_strings(details, true)
306 assert_equal ["<strong>User</strong> deleted (<del><i>Dave Lopper, Redmine Admin</i></del>)"], details_to_strings(details, false)
305 assert_equal ["<strong>User</strong> deleted (<del><i>Dave Lopper, Redmine Admin</i></del>)"], details_to_strings(details, false)
307 end
306 end
308
307
309 def test_details_to_strings_with_multiple_values_added_to_custom_field
308 def test_details_to_strings_with_multiple_values_added_to_custom_field
310 field = IssueCustomField.generate!(:name => 'User', :field_format => 'user', :multiple => true)
309 field = IssueCustomField.generate!(:name => 'User', :field_format => 'user', :multiple => true)
311 details = []
310 details = []
312 details << JournalDetail.new(:property => 'cf', :prop_key => field.id.to_s, :old_value => nil, :value => '1')
311 details << JournalDetail.new(:property => 'cf', :prop_key => field.id.to_s, :old_value => nil, :value => '1')
313 details << JournalDetail.new(:property => 'cf', :prop_key => field.id.to_s, :old_value => nil, :value => '3')
312 details << JournalDetail.new(:property => 'cf', :prop_key => field.id.to_s, :old_value => nil, :value => '3')
314
313
315 assert_equal ["User Dave Lopper, Redmine Admin added"], details_to_strings(details, true)
314 assert_equal ["User Dave Lopper, Redmine Admin added"], details_to_strings(details, true)
316 assert_equal ["<strong>User</strong> <i>Dave Lopper, Redmine Admin</i> added"], details_to_strings(details, false)
315 assert_equal ["<strong>User</strong> <i>Dave Lopper, Redmine Admin</i> added"], details_to_strings(details, false)
317 end
316 end
318
317
319 def test_details_to_strings_with_multiple_values_added_and_removed_from_custom_field
318 def test_details_to_strings_with_multiple_values_added_and_removed_from_custom_field
320 field = IssueCustomField.generate!(:name => 'User', :field_format => 'user', :multiple => true)
319 field = IssueCustomField.generate!(:name => 'User', :field_format => 'user', :multiple => true)
321 details = []
320 details = []
322 details << JournalDetail.new(:property => 'cf', :prop_key => field.id.to_s, :old_value => nil, :value => '1')
321 details << JournalDetail.new(:property => 'cf', :prop_key => field.id.to_s, :old_value => nil, :value => '1')
323 details << JournalDetail.new(:property => 'cf', :prop_key => field.id.to_s, :old_value => '2', :value => nil)
322 details << JournalDetail.new(:property => 'cf', :prop_key => field.id.to_s, :old_value => '2', :value => nil)
324 details << JournalDetail.new(:property => 'cf', :prop_key => field.id.to_s, :old_value => '3', :value => nil)
323 details << JournalDetail.new(:property => 'cf', :prop_key => field.id.to_s, :old_value => '3', :value => nil)
325
324
326 assert_equal [
325 assert_equal [
327 "User Redmine Admin added",
326 "User Redmine Admin added",
328 "User deleted (Dave Lopper, John Smith)"
327 "User deleted (Dave Lopper, John Smith)"
329 ], details_to_strings(details, true)
328 ], details_to_strings(details, true)
330 assert_equal [
329 assert_equal [
331 "<strong>User</strong> <i>Redmine Admin</i> added",
330 "<strong>User</strong> <i>Redmine Admin</i> added",
332 "<strong>User</strong> deleted (<del><i>Dave Lopper, John Smith</i></del>)"
331 "<strong>User</strong> deleted (<del><i>Dave Lopper, John Smith</i></del>)"
333 ], details_to_strings(details, false)
332 ], details_to_strings(details, false)
334 end
333 end
335
334
336 def test_find_name_by_reflection_should_return_nil_for_missing_record
335 def test_find_name_by_reflection_should_return_nil_for_missing_record
337 assert_nil find_name_by_reflection('status', 99)
336 assert_nil find_name_by_reflection('status', 99)
338 end
337 end
339 end
338 end
@@ -1,85 +1,84
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2016 Jean-Philippe Lang
2 # Copyright (C) 2006-2016 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require File.expand_path('../../../test_helper', __FILE__)
18 require File.expand_path('../../../test_helper', __FILE__)
19
19
20 class ProjectsHelperTest < Redmine::HelperTest
20 class ProjectsHelperTest < Redmine::HelperTest
21 include ApplicationHelper
21 include ApplicationHelper
22 include ProjectsHelper
22 include ProjectsHelper
23 include Redmine::I18n
23 include Redmine::I18n
24 include ERB::Util
24 include ERB::Util
25 include Rails.application.routes.url_helpers
25 include Rails.application.routes.url_helpers
26
26
27 fixtures :projects, :trackers, :issue_statuses, :issues,
27 fixtures :projects, :trackers, :issue_statuses, :issues,
28 :enumerations, :users, :issue_categories,
28 :enumerations, :users, :issue_categories,
29 :versions,
29 :versions,
30 :projects_trackers,
30 :projects_trackers,
31 :member_roles,
31 :member_roles,
32 :members,
32 :members,
33 :groups_users,
33 :groups_users,
34 :enabled_modules
34 :enabled_modules
35
35
36 def setup
36 def setup
37 super
37 super
38 set_language_if_valid('en')
38 set_language_if_valid('en')
39 User.current = nil
40 end
39 end
41
40
42 def test_link_to_version_within_project
41 def test_link_to_version_within_project
43 @project = Project.find(2)
42 @project = Project.find(2)
44 User.current = User.find(1)
43 User.current = User.find(1)
45 assert_equal '<a title="07/01/2006" href="/versions/5">Alpha</a>', link_to_version(Version.find(5))
44 assert_equal '<a title="07/01/2006" href="/versions/5">Alpha</a>', link_to_version(Version.find(5))
46 end
45 end
47
46
48 def test_link_to_version
47 def test_link_to_version
49 User.current = User.find(1)
48 User.current = User.find(1)
50 assert_equal '<a title="07/01/2006" href="/versions/5">OnlineStore - Alpha</a>', link_to_version(Version.find(5))
49 assert_equal '<a title="07/01/2006" href="/versions/5">OnlineStore - Alpha</a>', link_to_version(Version.find(5))
51 end
50 end
52
51
53 def test_link_to_version_without_effective_date
52 def test_link_to_version_without_effective_date
54 User.current = User.find(1)
53 User.current = User.find(1)
55 version = Version.find(5)
54 version = Version.find(5)
56 version.effective_date = nil
55 version.effective_date = nil
57 assert_equal '<a href="/versions/5">OnlineStore - Alpha</a>', link_to_version(version)
56 assert_equal '<a href="/versions/5">OnlineStore - Alpha</a>', link_to_version(version)
58 end
57 end
59
58
60 def test_link_to_private_version
59 def test_link_to_private_version
61 assert_equal 'OnlineStore - Alpha', link_to_version(Version.find(5))
60 assert_equal 'OnlineStore - Alpha', link_to_version(Version.find(5))
62 end
61 end
63
62
64 def test_link_to_version_invalid_version
63 def test_link_to_version_invalid_version
65 assert_equal '', link_to_version(Object)
64 assert_equal '', link_to_version(Object)
66 end
65 end
67
66
68 def test_format_version_name_within_project
67 def test_format_version_name_within_project
69 @project = Project.find(1)
68 @project = Project.find(1)
70 assert_equal "0.1", format_version_name(Version.find(1))
69 assert_equal "0.1", format_version_name(Version.find(1))
71 end
70 end
72
71
73 def test_format_version_name
72 def test_format_version_name
74 assert_equal "eCookbook - 0.1", format_version_name(Version.find(1))
73 assert_equal "eCookbook - 0.1", format_version_name(Version.find(1))
75 end
74 end
76
75
77 def test_format_version_name_for_system_version
76 def test_format_version_name_for_system_version
78 assert_equal "OnlineStore - Systemwide visible version", format_version_name(Version.find(7))
77 assert_equal "OnlineStore - Systemwide visible version", format_version_name(Version.find(7))
79 end
78 end
80
79
81 def test_version_options_for_select_with_no_versions
80 def test_version_options_for_select_with_no_versions
82 assert_equal '', version_options_for_select([])
81 assert_equal '', version_options_for_select([])
83 assert_equal '', version_options_for_select([], Version.find(1))
82 assert_equal '', version_options_for_select([], Version.find(1))
84 end
83 end
85 end
84 end
@@ -1,109 +1,110
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2016 Jean-Philippe Lang
2 # Copyright (C) 2006-2016 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require File.expand_path('../../../test_helper', __FILE__)
18 require File.expand_path('../../../test_helper', __FILE__)
19
19
20 class SortHelperTest < Redmine::HelperTest
20 class SortHelperTest < Redmine::HelperTest
21 include SortHelper
21 include SortHelper
22 include Redmine::I18n
22 include Redmine::I18n
23 include ERB::Util
23 include ERB::Util
24
24
25 def setup
25 def setup
26 super
26 @session = nil
27 @session = nil
27 @sort_param = nil
28 @sort_param = nil
28 end
29 end
29
30
30 def test_default_sort_clause_with_array
31 def test_default_sort_clause_with_array
31 sort_init 'attr1', 'desc'
32 sort_init 'attr1', 'desc'
32 sort_update(['attr1', 'attr2'])
33 sort_update(['attr1', 'attr2'])
33
34
34 assert_equal ['attr1 DESC'], sort_clause
35 assert_equal ['attr1 DESC'], sort_clause
35 end
36 end
36
37
37 def test_default_sort_clause_with_hash
38 def test_default_sort_clause_with_hash
38 sort_init 'attr1', 'desc'
39 sort_init 'attr1', 'desc'
39 sort_update({'attr1' => 'table1.attr1', 'attr2' => 'table2.attr2'})
40 sort_update({'attr1' => 'table1.attr1', 'attr2' => 'table2.attr2'})
40
41
41 assert_equal ['table1.attr1 DESC'], sort_clause
42 assert_equal ['table1.attr1 DESC'], sort_clause
42 end
43 end
43
44
44 def test_default_sort_clause_with_multiple_columns
45 def test_default_sort_clause_with_multiple_columns
45 sort_init 'attr1', 'desc'
46 sort_init 'attr1', 'desc'
46 sort_update({'attr1' => ['table1.attr1', 'table1.attr2'], 'attr2' => 'table2.attr2'})
47 sort_update({'attr1' => ['table1.attr1', 'table1.attr2'], 'attr2' => 'table2.attr2'})
47
48
48 assert_equal ['table1.attr1 DESC', 'table1.attr2 DESC'], sort_clause
49 assert_equal ['table1.attr1 DESC', 'table1.attr2 DESC'], sort_clause
49 end
50 end
50
51
51 def test_params_sort
52 def test_params_sort
52 @sort_param = 'attr1,attr2:desc'
53 @sort_param = 'attr1,attr2:desc'
53
54
54 sort_init 'attr1', 'desc'
55 sort_init 'attr1', 'desc'
55 sort_update({'attr1' => 'table1.attr1', 'attr2' => 'table2.attr2'})
56 sort_update({'attr1' => 'table1.attr1', 'attr2' => 'table2.attr2'})
56
57
57 assert_equal ['table1.attr1 ASC', 'table2.attr2 DESC'], sort_clause
58 assert_equal ['table1.attr1 ASC', 'table2.attr2 DESC'], sort_clause
58 assert_equal 'attr1,attr2:desc', @session['foo_bar_sort']
59 assert_equal 'attr1,attr2:desc', @session['foo_bar_sort']
59 end
60 end
60
61
61 def test_invalid_params_sort
62 def test_invalid_params_sort
62 @sort_param = 'invalid_key'
63 @sort_param = 'invalid_key'
63
64
64 sort_init 'attr1', 'desc'
65 sort_init 'attr1', 'desc'
65 sort_update({'attr1' => 'table1.attr1', 'attr2' => 'table2.attr2'})
66 sort_update({'attr1' => 'table1.attr1', 'attr2' => 'table2.attr2'})
66
67
67 assert_equal ['table1.attr1 DESC'], sort_clause
68 assert_equal ['table1.attr1 DESC'], sort_clause
68 assert_equal 'attr1:desc', @session['foo_bar_sort']
69 assert_equal 'attr1:desc', @session['foo_bar_sort']
69 end
70 end
70
71
71 def test_invalid_order_params_sort
72 def test_invalid_order_params_sort
72 @sort_param = 'attr1:foo:bar,attr2'
73 @sort_param = 'attr1:foo:bar,attr2'
73
74
74 sort_init 'attr1', 'desc'
75 sort_init 'attr1', 'desc'
75 sort_update({'attr1' => 'table1.attr1', 'attr2' => 'table2.attr2'})
76 sort_update({'attr1' => 'table1.attr1', 'attr2' => 'table2.attr2'})
76
77
77 assert_equal ['table1.attr1 ASC', 'table2.attr2 ASC'], sort_clause
78 assert_equal ['table1.attr1 ASC', 'table2.attr2 ASC'], sort_clause
78 assert_equal 'attr1,attr2', @session['foo_bar_sort']
79 assert_equal 'attr1,attr2', @session['foo_bar_sort']
79 end
80 end
80
81
81 def test_sort_css_without_params_should_use_default_sort
82 def test_sort_css_without_params_should_use_default_sort
82 sort_init 'attr1', 'desc'
83 sort_init 'attr1', 'desc'
83 sort_update(['attr1', 'attr2'])
84 sort_update(['attr1', 'attr2'])
84
85
85 assert_equal 'sort-by-attr1 sort-desc', sort_css_classes
86 assert_equal 'sort-by-attr1 sort-desc', sort_css_classes
86 end
87 end
87
88
88 def test_sort_css_should_use_params
89 def test_sort_css_should_use_params
89 @sort_param = 'attr2,attr1'
90 @sort_param = 'attr2,attr1'
90 sort_init 'attr1', 'desc'
91 sort_init 'attr1', 'desc'
91 sort_update(['attr1', 'attr2'])
92 sort_update(['attr1', 'attr2'])
92
93
93 assert_equal 'sort-by-attr2 sort-asc', sort_css_classes
94 assert_equal 'sort-by-attr2 sort-asc', sort_css_classes
94 end
95 end
95
96
96 def test_sort_css_should_dasherize_sort_name
97 def test_sort_css_should_dasherize_sort_name
97 sort_init 'foo_bar'
98 sort_init 'foo_bar'
98 sort_update(['foo_bar'])
99 sort_update(['foo_bar'])
99
100
100 assert_equal 'sort-by-foo-bar sort-asc', sort_css_classes
101 assert_equal 'sort-by-foo-bar sort-asc', sort_css_classes
101 end
102 end
102
103
103 private
104 private
104
105
105 def controller_name; 'foo'; end
106 def controller_name; 'foo'; end
106 def action_name; 'bar'; end
107 def action_name; 'bar'; end
107 def params; {:sort => @sort_param}; end
108 def params; {:sort => @sort_param}; end
108 def session; @session ||= {}; end
109 def session; @session ||= {}; end
109 end
110 end
@@ -1,58 +1,54
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2016 Jean-Philippe Lang
2 # Copyright (C) 2006-2016 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require File.expand_path('../../../test_helper', __FILE__)
18 require File.expand_path('../../../test_helper', __FILE__)
19
19
20 class TimelogHelperTest < Redmine::HelperTest
20 class TimelogHelperTest < Redmine::HelperTest
21 include TimelogHelper
21 include TimelogHelper
22 include Redmine::I18n
22 include Redmine::I18n
23 include ActionView::Helpers::TextHelper
23 include ActionView::Helpers::TextHelper
24 include ActionView::Helpers::DateHelper
24 include ActionView::Helpers::DateHelper
25 include ERB::Util
25 include ERB::Util
26
26
27 fixtures :projects, :roles, :enabled_modules, :users,
27 fixtures :projects, :roles, :enabled_modules, :users,
28 :repositories, :changesets,
28 :repositories, :changesets,
29 :trackers, :issue_statuses, :issues, :versions, :documents,
29 :trackers, :issue_statuses, :issues, :versions, :documents,
30 :wikis, :wiki_pages, :wiki_contents,
30 :wikis, :wiki_pages, :wiki_contents,
31 :boards, :messages,
31 :boards, :messages,
32 :attachments,
32 :attachments,
33 :enumerations
33 :enumerations
34
34
35 def setup
36 super
37 end
38
39 def test_activities_collection_for_select_options_should_return_array_of_activity_names_and_ids
35 def test_activities_collection_for_select_options_should_return_array_of_activity_names_and_ids
40 activities = activity_collection_for_select_options
36 activities = activity_collection_for_select_options
41 assert activities.include?(["Design", 9])
37 assert activities.include?(["Design", 9])
42 assert activities.include?(["Development", 10])
38 assert activities.include?(["Development", 10])
43 end
39 end
44
40
45 def test_activities_collection_for_select_options_should_not_include_inactive_activities
41 def test_activities_collection_for_select_options_should_not_include_inactive_activities
46 activities = activity_collection_for_select_options
42 activities = activity_collection_for_select_options
47 assert !activities.include?(["Inactive Activity", 14])
43 assert !activities.include?(["Inactive Activity", 14])
48 end
44 end
49
45
50 def test_activities_collection_for_select_options_should_use_the_projects_override
46 def test_activities_collection_for_select_options_should_use_the_projects_override
51 project = Project.find(1)
47 project = Project.find(1)
52 override_activity = TimeEntryActivity.create!({:name => "Design override", :parent => TimeEntryActivity.find_by_name("Design"), :project => project})
48 override_activity = TimeEntryActivity.create!({:name => "Design override", :parent => TimeEntryActivity.find_by_name("Design"), :project => project})
53
49
54 activities = activity_collection_for_select_options(nil, project)
50 activities = activity_collection_for_select_options(nil, project)
55 assert !activities.include?(["Design", 9]), "System activity found in: " + activities.inspect
51 assert !activities.include?(["Design", 9]), "System activity found in: " + activities.inspect
56 assert activities.include?(["Design override", override_activity.id]), "Override activity not found in: " + activities.inspect
52 assert activities.include?(["Design override", override_activity.id]), "Override activity not found in: " + activities.inspect
57 end
53 end
58 end
54 end
@@ -1,74 +1,73
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2016 Jean-Philippe Lang
2 # Copyright (C) 2006-2016 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require File.expand_path('../../../test_helper', __FILE__)
18 require File.expand_path('../../../test_helper', __FILE__)
19
19
20 class WatchersHelperTest < Redmine::HelperTest
20 class WatchersHelperTest < Redmine::HelperTest
21 include WatchersHelper
21 include WatchersHelper
22 include Redmine::I18n
22 include Redmine::I18n
23 include Rails.application.routes.url_helpers
23 include Rails.application.routes.url_helpers
24
24
25 fixtures :users, :issues
25 fixtures :users, :issues
26
26
27 def setup
27 def setup
28 super
28 super
29 set_language_if_valid('en')
29 set_language_if_valid('en')
30 User.current = nil
31 end
30 end
32
31
33 test '#watcher_link with a non-watched object' do
32 test '#watcher_link with a non-watched object' do
34 expected = link_to(
33 expected = link_to(
35 "Watch",
34 "Watch",
36 "/watchers/watch?object_id=1&object_type=issue",
35 "/watchers/watch?object_id=1&object_type=issue",
37 :remote => true, :method => 'post', :class => "issue-1-watcher icon icon-fav-off"
36 :remote => true, :method => 'post', :class => "issue-1-watcher icon icon-fav-off"
38 )
37 )
39 assert_equal expected, watcher_link(Issue.find(1), User.find(1))
38 assert_equal expected, watcher_link(Issue.find(1), User.find(1))
40 end
39 end
41
40
42 test '#watcher_link with a single objet array' do
41 test '#watcher_link with a single objet array' do
43 expected = link_to(
42 expected = link_to(
44 "Watch",
43 "Watch",
45 "/watchers/watch?object_id=1&object_type=issue",
44 "/watchers/watch?object_id=1&object_type=issue",
46 :remote => true, :method => 'post', :class => "issue-1-watcher icon icon-fav-off"
45 :remote => true, :method => 'post', :class => "issue-1-watcher icon icon-fav-off"
47 )
46 )
48 assert_equal expected, watcher_link([Issue.find(1)], User.find(1))
47 assert_equal expected, watcher_link([Issue.find(1)], User.find(1))
49 end
48 end
50
49
51 test '#watcher_link with a multiple objets array' do
50 test '#watcher_link with a multiple objets array' do
52 expected = link_to(
51 expected = link_to(
53 "Watch",
52 "Watch",
54 "/watchers/watch?object_id%5B%5D=1&object_id%5B%5D=3&object_type=issue",
53 "/watchers/watch?object_id%5B%5D=1&object_id%5B%5D=3&object_type=issue",
55 :remote => true, :method => 'post', :class => "issue-bulk-watcher icon icon-fav-off"
54 :remote => true, :method => 'post', :class => "issue-bulk-watcher icon icon-fav-off"
56 )
55 )
57 assert_equal expected, watcher_link([Issue.find(1), Issue.find(3)], User.find(1))
56 assert_equal expected, watcher_link([Issue.find(1), Issue.find(3)], User.find(1))
58 end
57 end
59
58
60 def test_watcher_link_with_nil_should_return_empty_string
59 def test_watcher_link_with_nil_should_return_empty_string
61 assert_equal '', watcher_link(nil, User.find(1))
60 assert_equal '', watcher_link(nil, User.find(1))
62 end
61 end
63
62
64 test '#watcher_link with a watched object' do
63 test '#watcher_link with a watched object' do
65 Watcher.create!(:watchable => Issue.find(1), :user => User.find(1))
64 Watcher.create!(:watchable => Issue.find(1), :user => User.find(1))
66
65
67 expected = link_to(
66 expected = link_to(
68 "Unwatch",
67 "Unwatch",
69 "/watchers/watch?object_id=1&object_type=issue",
68 "/watchers/watch?object_id=1&object_type=issue",
70 :remote => true, :method => 'delete', :class => "issue-1-watcher icon icon-fav"
69 :remote => true, :method => 'delete', :class => "issue-1-watcher icon icon-fav"
71 )
70 )
72 assert_equal expected, watcher_link(Issue.find(1), User.find(1))
71 assert_equal expected, watcher_link(Issue.find(1), User.find(1))
73 end
72 end
74 end
73 end
General Comments 0
You need to be logged in to leave comments. Login now