##// END OF EJS Templates
Fixed: Export CSV - Custom field true/false not using translation (#16081)....
Jean-Philippe Lang -
r12621:1114bf5e99e4
parent child
Show More
@@ -1,198 +1,202
1 1 # encoding: utf-8
2 2 #
3 3 # Redmine - project management software
4 4 # Copyright (C) 2006-2014 Jean-Philippe Lang
5 5 #
6 6 # This program is free software; you can redistribute it and/or
7 7 # modify it under the terms of the GNU General Public License
8 8 # as published by the Free Software Foundation; either version 2
9 9 # of the License, or (at your option) any later version.
10 10 #
11 11 # This program is distributed in the hope that it will be useful,
12 12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 14 # GNU General Public License for more details.
15 15 #
16 16 # You should have received a copy of the GNU General Public License
17 17 # along with this program; if not, write to the Free Software
18 18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 19
20 20 module QueriesHelper
21 21 def filters_options_for_select(query)
22 22 options_for_select(filters_options(query))
23 23 end
24 24
25 25 def filters_options(query)
26 26 options = [[]]
27 27 options += query.available_filters.map do |field, field_options|
28 28 [field_options[:name], field]
29 29 end
30 30 end
31 31
32 32 def query_filters_hidden_tags(query)
33 33 tags = ''.html_safe
34 34 query.filters.each do |field, options|
35 35 tags << hidden_field_tag("f[]", field, :id => nil)
36 36 tags << hidden_field_tag("op[#{field}]", options[:operator], :id => nil)
37 37 options[:values].each do |value|
38 38 tags << hidden_field_tag("v[#{field}][]", value, :id => nil)
39 39 end
40 40 end
41 41 tags
42 42 end
43 43
44 44 def query_columns_hidden_tags(query)
45 45 tags = ''.html_safe
46 46 query.columns.each do |column|
47 47 tags << hidden_field_tag("c[]", column.name, :id => nil)
48 48 end
49 49 tags
50 50 end
51 51
52 52 def query_hidden_tags(query)
53 53 query_filters_hidden_tags(query) + query_columns_hidden_tags(query)
54 54 end
55 55
56 56 def available_block_columns_tags(query)
57 57 tags = ''.html_safe
58 58 query.available_block_columns.each do |column|
59 59 tags << content_tag('label', check_box_tag('c[]', column.name.to_s, query.has_column?(column), :id => nil) + " #{column.caption}", :class => 'inline')
60 60 end
61 61 tags
62 62 end
63 63
64 64 def query_available_inline_columns_options(query)
65 65 (query.available_inline_columns - query.columns).reject(&:frozen?).collect {|column| [column.caption, column.name]}
66 66 end
67 67
68 68 def query_selected_inline_columns_options(query)
69 69 (query.inline_columns & query.available_inline_columns).reject(&:frozen?).collect {|column| [column.caption, column.name]}
70 70 end
71 71
72 72 def render_query_columns_selection(query, options={})
73 73 tag_name = (options[:name] || 'c') + '[]'
74 74 render :partial => 'queries/columns', :locals => {:query => query, :tag_name => tag_name}
75 75 end
76 76
77 77 def column_header(column)
78 78 column.sortable ? sort_header_tag(column.name.to_s, :caption => column.caption,
79 79 :default_order => column.default_order) :
80 80 content_tag('th', h(column.caption))
81 81 end
82 82
83 83 def column_content(column, issue)
84 84 value = column.value(issue)
85 85 if value.is_a?(Array)
86 86 value.collect {|v| column_value(column, issue, v)}.compact.join(', ').html_safe
87 87 else
88 88 column_value(column, issue, value)
89 89 end
90 90 end
91 91
92 92 def column_value(column, issue, value)
93 93 case column.name
94 94 when :id
95 95 link_to value, issue_path(issue)
96 96 when :subject
97 97 link_to value, issue_path(issue)
98 98 when :description
99 99 issue.description? ? content_tag('div', textilizable(issue, :description), :class => "wiki") : ''
100 100 when :done_ratio
101 101 progress_bar(value, :width => '80px')
102 102 when :relations
103 103 other = value.other_issue(issue)
104 104 content_tag('span',
105 105 (l(value.label_for(issue)) + " " + link_to_issue(other, :subject => false, :tracker => false)).html_safe,
106 106 :class => value.css_classes_for(issue))
107 107 else
108 108 format_object(value)
109 109 end
110 110 end
111 111
112 112 def csv_content(column, issue)
113 113 value = column.value(issue)
114 114 if value.is_a?(Array)
115 115 value.collect {|v| csv_value(column, issue, v)}.compact.join(', ')
116 116 else
117 117 csv_value(column, issue, value)
118 118 end
119 119 end
120 120
121 121 def csv_value(column, issue, value)
122 122 case value.class.name
123 123 when 'Time'
124 124 format_time(value)
125 125 when 'Date'
126 126 format_date(value)
127 127 when 'Float'
128 128 sprintf("%.2f", value).gsub('.', l(:general_csv_decimal_separator))
129 129 when 'IssueRelation'
130 130 other = value.other_issue(issue)
131 131 l(value.label_for(issue)) + " ##{other.id}"
132 when 'TrueClass'
133 l(:general_text_Yes)
134 when 'FalseClass'
135 l(:general_text_No)
132 136 else
133 137 value.to_s
134 138 end
135 139 end
136 140
137 141 def query_to_csv(items, query, options={})
138 142 encoding = l(:general_csv_encoding)
139 143 columns = (options[:columns] == 'all' ? query.available_inline_columns : query.inline_columns)
140 144 query.available_block_columns.each do |column|
141 145 if options[column.name].present?
142 146 columns << column
143 147 end
144 148 end
145 149
146 150 export = FCSV.generate(:col_sep => l(:general_csv_separator)) do |csv|
147 151 # csv header fields
148 152 csv << columns.collect {|c| Redmine::CodesetUtil.from_utf8(c.caption.to_s, encoding) }
149 153 # csv lines
150 154 items.each do |item|
151 155 csv << columns.collect {|c| Redmine::CodesetUtil.from_utf8(csv_content(c, item), encoding) }
152 156 end
153 157 end
154 158 export
155 159 end
156 160
157 161 # Retrieve query from session or build a new query
158 162 def retrieve_query
159 163 if !params[:query_id].blank?
160 164 cond = "project_id IS NULL"
161 165 cond << " OR project_id = #{@project.id}" if @project
162 166 @query = IssueQuery.where(cond).find(params[:query_id])
163 167 raise ::Unauthorized unless @query.visible?
164 168 @query.project = @project
165 169 session[:query] = {:id => @query.id, :project_id => @query.project_id}
166 170 sort_clear
167 171 elsif api_request? || params[:set_filter] || session[:query].nil? || session[:query][:project_id] != (@project ? @project.id : nil)
168 172 # Give it a name, required to be valid
169 173 @query = IssueQuery.new(:name => "_")
170 174 @query.project = @project
171 175 @query.build_from_params(params)
172 176 session[:query] = {:project_id => @query.project_id, :filters => @query.filters, :group_by => @query.group_by, :column_names => @query.column_names}
173 177 else
174 178 # retrieve from session
175 179 @query = nil
176 180 @query = IssueQuery.find_by_id(session[:query][:id]) if session[:query][:id]
177 181 @query ||= IssueQuery.new(:name => "_", :filters => session[:query][:filters], :group_by => session[:query][:group_by], :column_names => session[:query][:column_names])
178 182 @query.project = @project
179 183 end
180 184 end
181 185
182 186 def retrieve_query_from_session
183 187 if session[:query]
184 188 if session[:query][:id]
185 189 @query = IssueQuery.find_by_id(session[:query][:id])
186 190 return unless @query
187 191 else
188 192 @query = IssueQuery.new(:name => "_", :filters => session[:query][:filters], :group_by => session[:query][:group_by], :column_names => session[:query][:column_names])
189 193 end
190 194 if session[:query].has_key?(:project_id)
191 195 @query.project_id = session[:query][:project_id]
192 196 else
193 197 @query.project = @project
194 198 end
195 199 @query
196 200 end
197 201 end
198 202 end
@@ -1,486 +1,494
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2014 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 'shoulda'
19 19 ENV["RAILS_ENV"] = "test"
20 20 require File.expand_path(File.dirname(__FILE__) + "/../config/environment")
21 21 require 'rails/test_help'
22 22 require Rails.root.join('test', 'mocks', 'open_id_authentication_mock.rb').to_s
23 23
24 24 require File.expand_path(File.dirname(__FILE__) + '/object_helpers')
25 25 include ObjectHelpers
26 26
27 27 require 'awesome_nested_set/version'
28 28
29 29 class ActiveSupport::TestCase
30 30 include ActionDispatch::TestProcess
31 31
32 32 self.use_transactional_fixtures = true
33 33 self.use_instantiated_fixtures = false
34 34
35 35 ESCAPED_CANT = 'can&#x27;t'
36 36 ESCAPED_UCANT = 'Can&#x27;t'
37 37 # Rails 4.0.2
38 38 #ESCAPED_CANT = 'can&#39;t'
39 39 #ESCAPED_UCANT = 'Can&#39;t'
40 40
41 41 def log_user(login, password)
42 42 User.anonymous
43 43 get "/login"
44 44 assert_equal nil, session[:user_id]
45 45 assert_response :success
46 46 assert_template "account/login"
47 47 post "/login", :username => login, :password => password
48 48 assert_equal login, User.find(session[:user_id]).login
49 49 end
50 50
51 51 def uploaded_test_file(name, mime)
52 52 fixture_file_upload("files/#{name}", mime, true)
53 53 end
54 54
55 55 def credentials(user, password=nil)
56 56 {'HTTP_AUTHORIZATION' => ActionController::HttpAuthentication::Basic.encode_credentials(user, password || user)}
57 57 end
58 58
59 59 # Mock out a file
60 60 def self.mock_file
61 61 file = 'a_file.png'
62 62 file.stubs(:size).returns(32)
63 63 file.stubs(:original_filename).returns('a_file.png')
64 64 file.stubs(:content_type).returns('image/png')
65 65 file.stubs(:read).returns(false)
66 66 file
67 67 end
68 68
69 69 def mock_file
70 70 self.class.mock_file
71 71 end
72 72
73 73 def mock_file_with_options(options={})
74 74 file = ''
75 75 file.stubs(:size).returns(32)
76 76 original_filename = options[:original_filename] || nil
77 77 file.stubs(:original_filename).returns(original_filename)
78 78 content_type = options[:content_type] || nil
79 79 file.stubs(:content_type).returns(content_type)
80 80 file.stubs(:read).returns(false)
81 81 file
82 82 end
83 83
84 84 # Use a temporary directory for attachment related tests
85 85 def set_tmp_attachments_directory
86 86 Dir.mkdir "#{Rails.root}/tmp/test" unless File.directory?("#{Rails.root}/tmp/test")
87 87 unless File.directory?("#{Rails.root}/tmp/test/attachments")
88 88 Dir.mkdir "#{Rails.root}/tmp/test/attachments"
89 89 end
90 90 Attachment.storage_path = "#{Rails.root}/tmp/test/attachments"
91 91 end
92 92
93 93 def set_fixtures_attachments_directory
94 94 Attachment.storage_path = "#{Rails.root}/test/fixtures/files"
95 95 end
96 96
97 97 def with_settings(options, &block)
98 98 saved_settings = options.keys.inject({}) do |h, k|
99 99 h[k] = case Setting[k]
100 100 when Symbol, false, true, nil
101 101 Setting[k]
102 102 else
103 103 Setting[k].dup
104 104 end
105 105 h
106 106 end
107 107 options.each {|k, v| Setting[k] = v}
108 108 yield
109 109 ensure
110 110 saved_settings.each {|k, v| Setting[k] = v} if saved_settings
111 111 end
112 112
113 113 # Yields the block with user as the current user
114 114 def with_current_user(user, &block)
115 115 saved_user = User.current
116 116 User.current = user
117 117 yield
118 118 ensure
119 119 User.current = saved_user
120 120 end
121 121
122 def with_locale(locale, &block)
123 saved_localed = ::I18n.locale
124 ::I18n.locale = locale
125 yield
126 ensure
127 ::I18n.locale = saved_localed
128 end
129
122 130 def change_user_password(login, new_password)
123 131 user = User.where(:login => login).first
124 132 user.password, user.password_confirmation = new_password, new_password
125 133 user.save!
126 134 end
127 135
128 136 def self.ldap_configured?
129 137 @test_ldap = Net::LDAP.new(:host => '127.0.0.1', :port => 389)
130 138 return @test_ldap.bind
131 139 rescue Exception => e
132 140 # LDAP is not listening
133 141 return nil
134 142 end
135 143
136 144 def self.convert_installed?
137 145 Redmine::Thumbnail.convert_available?
138 146 end
139 147
140 148 # Returns the path to the test +vendor+ repository
141 149 def self.repository_path(vendor)
142 150 Rails.root.join("tmp/test/#{vendor.downcase}_repository").to_s
143 151 end
144 152
145 153 # Returns the url of the subversion test repository
146 154 def self.subversion_repository_url
147 155 path = repository_path('subversion')
148 156 path = '/' + path unless path.starts_with?('/')
149 157 "file://#{path}"
150 158 end
151 159
152 160 # Returns true if the +vendor+ test repository is configured
153 161 def self.repository_configured?(vendor)
154 162 File.directory?(repository_path(vendor))
155 163 end
156 164
157 165 def repository_path_hash(arr)
158 166 hs = {}
159 167 hs[:path] = arr.join("/")
160 168 hs[:param] = arr.join("/")
161 169 hs
162 170 end
163 171
164 172 def assert_save(object)
165 173 saved = object.save
166 174 message = "#{object.class} could not be saved"
167 175 errors = object.errors.full_messages.map {|m| "- #{m}"}
168 176 message << ":\n#{errors.join("\n")}" if errors.any?
169 177 assert_equal true, saved, message
170 178 end
171 179
172 180 def assert_error_tag(options={})
173 181 assert_tag({:attributes => { :id => 'errorExplanation' }}.merge(options))
174 182 end
175 183
176 184 def assert_include(expected, s, message=nil)
177 185 assert s.include?(expected), (message || "\"#{expected}\" not found in \"#{s}\"")
178 186 end
179 187
180 188 def assert_not_include(expected, s, message=nil)
181 189 assert !s.include?(expected), (message || "\"#{expected}\" found in \"#{s}\"")
182 190 end
183 191
184 192 def assert_select_in(text, *args, &block)
185 193 d = HTML::Document.new(CGI::unescapeHTML(String.new(text))).root
186 194 assert_select(d, *args, &block)
187 195 end
188 196
189 197 def assert_mail_body_match(expected, mail, message=nil)
190 198 if expected.is_a?(String)
191 199 assert_include expected, mail_body(mail), message
192 200 else
193 201 assert_match expected, mail_body(mail), message
194 202 end
195 203 end
196 204
197 205 def assert_mail_body_no_match(expected, mail, message=nil)
198 206 if expected.is_a?(String)
199 207 assert_not_include expected, mail_body(mail), message
200 208 else
201 209 assert_no_match expected, mail_body(mail), message
202 210 end
203 211 end
204 212
205 213 def mail_body(mail)
206 214 mail.parts.first.body.encoded
207 215 end
208 216
209 217 # awesome_nested_set new node lft and rgt value changed this refactor revision.
210 218 # https://github.com/collectiveidea/awesome_nested_set/commit/199fca9bb938e40200cd90714dc69247ef017c61
211 219 # The reason of behavior change is that "self.class.base_class.unscoped" was added to this line.
212 220 # https://github.com/collectiveidea/awesome_nested_set/commit/199fca9bb9#diff-f61b59a5e6319024e211b0ffdd0e4ef1R273
213 221 # It seems correct behavior because of this line comment.
214 222 # https://github.com/collectiveidea/awesome_nested_set/blame/199fca9bb9/lib/awesome_nested_set/model.rb#L278
215 223 def new_issue_lft
216 224 ::AwesomeNestedSet::VERSION > "2.1.6" ? Issue.maximum(:rgt) + 1 : 1
217 225 end
218 226 end
219 227
220 228 module Redmine
221 229 module ApiTest
222 230 # Base class for API tests
223 231 class Base < ActionDispatch::IntegrationTest
224 232 # Test that a request allows the three types of API authentication
225 233 #
226 234 # * HTTP Basic with username and password
227 235 # * HTTP Basic with an api key for the username
228 236 # * Key based with the key=X parameter
229 237 #
230 238 # @param [Symbol] http_method the HTTP method for request (:get, :post, :put, :delete)
231 239 # @param [String] url the request url
232 240 # @param [optional, Hash] parameters additional request parameters
233 241 # @param [optional, Hash] options additional options
234 242 # @option options [Symbol] :success_code Successful response code (:success)
235 243 # @option options [Symbol] :failure_code Failure response code (:unauthorized)
236 244 def self.should_allow_api_authentication(http_method, url, parameters={}, options={})
237 245 should_allow_http_basic_auth_with_username_and_password(http_method, url, parameters, options)
238 246 should_allow_http_basic_auth_with_key(http_method, url, parameters, options)
239 247 should_allow_key_based_auth(http_method, url, parameters, options)
240 248 end
241 249
242 250 # Test that a request allows the username and password for HTTP BASIC
243 251 #
244 252 # @param [Symbol] http_method the HTTP method for request (:get, :post, :put, :delete)
245 253 # @param [String] url the request url
246 254 # @param [optional, Hash] parameters additional request parameters
247 255 # @param [optional, Hash] options additional options
248 256 # @option options [Symbol] :success_code Successful response code (:success)
249 257 # @option options [Symbol] :failure_code Failure response code (:unauthorized)
250 258 def self.should_allow_http_basic_auth_with_username_and_password(http_method, url, parameters={}, options={})
251 259 success_code = options[:success_code] || :success
252 260 failure_code = options[:failure_code] || :unauthorized
253 261
254 262 context "should allow http basic auth using a username and password for #{http_method} #{url}" do
255 263 context "with a valid HTTP authentication" do
256 264 setup do
257 265 @user = User.generate! do |user|
258 266 user.admin = true
259 267 user.password = 'my_password'
260 268 end
261 269 send(http_method, url, parameters, credentials(@user.login, 'my_password'))
262 270 end
263 271
264 272 should_respond_with success_code
265 273 should_respond_with_content_type_based_on_url(url)
266 274 should "login as the user" do
267 275 assert_equal @user, User.current
268 276 end
269 277 end
270 278
271 279 context "with an invalid HTTP authentication" do
272 280 setup do
273 281 @user = User.generate!
274 282 send(http_method, url, parameters, credentials(@user.login, 'wrong_password'))
275 283 end
276 284
277 285 should_respond_with failure_code
278 286 should_respond_with_content_type_based_on_url(url)
279 287 should "not login as the user" do
280 288 assert_equal User.anonymous, User.current
281 289 end
282 290 end
283 291
284 292 context "without credentials" do
285 293 setup do
286 294 send(http_method, url, parameters)
287 295 end
288 296
289 297 should_respond_with failure_code
290 298 should_respond_with_content_type_based_on_url(url)
291 299 should "include_www_authenticate_header" do
292 300 assert @controller.response.headers.has_key?('WWW-Authenticate')
293 301 end
294 302 end
295 303 end
296 304 end
297 305
298 306 # Test that a request allows the API key with HTTP BASIC
299 307 #
300 308 # @param [Symbol] http_method the HTTP method for request (:get, :post, :put, :delete)
301 309 # @param [String] url the request url
302 310 # @param [optional, Hash] parameters additional request parameters
303 311 # @param [optional, Hash] options additional options
304 312 # @option options [Symbol] :success_code Successful response code (:success)
305 313 # @option options [Symbol] :failure_code Failure response code (:unauthorized)
306 314 def self.should_allow_http_basic_auth_with_key(http_method, url, parameters={}, options={})
307 315 success_code = options[:success_code] || :success
308 316 failure_code = options[:failure_code] || :unauthorized
309 317
310 318 context "should allow http basic auth with a key for #{http_method} #{url}" do
311 319 context "with a valid HTTP authentication using the API token" do
312 320 setup do
313 321 @user = User.generate! do |user|
314 322 user.admin = true
315 323 end
316 324 @token = Token.create!(:user => @user, :action => 'api')
317 325 send(http_method, url, parameters, credentials(@token.value, 'X'))
318 326 end
319 327 should_respond_with success_code
320 328 should_respond_with_content_type_based_on_url(url)
321 329 should_be_a_valid_response_string_based_on_url(url)
322 330 should "login as the user" do
323 331 assert_equal @user, User.current
324 332 end
325 333 end
326 334
327 335 context "with an invalid HTTP authentication" do
328 336 setup do
329 337 @user = User.generate!
330 338 @token = Token.create!(:user => @user, :action => 'feeds')
331 339 send(http_method, url, parameters, credentials(@token.value, 'X'))
332 340 end
333 341 should_respond_with failure_code
334 342 should_respond_with_content_type_based_on_url(url)
335 343 should "not login as the user" do
336 344 assert_equal User.anonymous, User.current
337 345 end
338 346 end
339 347 end
340 348 end
341 349
342 350 # Test that a request allows full key authentication
343 351 #
344 352 # @param [Symbol] http_method the HTTP method for request (:get, :post, :put, :delete)
345 353 # @param [String] url the request url, without the key=ZXY parameter
346 354 # @param [optional, Hash] parameters additional request parameters
347 355 # @param [optional, Hash] options additional options
348 356 # @option options [Symbol] :success_code Successful response code (:success)
349 357 # @option options [Symbol] :failure_code Failure response code (:unauthorized)
350 358 def self.should_allow_key_based_auth(http_method, url, parameters={}, options={})
351 359 success_code = options[:success_code] || :success
352 360 failure_code = options[:failure_code] || :unauthorized
353 361
354 362 context "should allow key based auth using key=X for #{http_method} #{url}" do
355 363 context "with a valid api token" do
356 364 setup do
357 365 @user = User.generate! do |user|
358 366 user.admin = true
359 367 end
360 368 @token = Token.create!(:user => @user, :action => 'api')
361 369 # Simple url parse to add on ?key= or &key=
362 370 request_url = if url.match(/\?/)
363 371 url + "&key=#{@token.value}"
364 372 else
365 373 url + "?key=#{@token.value}"
366 374 end
367 375 send(http_method, request_url, parameters)
368 376 end
369 377 should_respond_with success_code
370 378 should_respond_with_content_type_based_on_url(url)
371 379 should_be_a_valid_response_string_based_on_url(url)
372 380 should "login as the user" do
373 381 assert_equal @user, User.current
374 382 end
375 383 end
376 384
377 385 context "with an invalid api token" do
378 386 setup do
379 387 @user = User.generate! do |user|
380 388 user.admin = true
381 389 end
382 390 @token = Token.create!(:user => @user, :action => 'feeds')
383 391 # Simple url parse to add on ?key= or &key=
384 392 request_url = if url.match(/\?/)
385 393 url + "&key=#{@token.value}"
386 394 else
387 395 url + "?key=#{@token.value}"
388 396 end
389 397 send(http_method, request_url, parameters)
390 398 end
391 399 should_respond_with failure_code
392 400 should_respond_with_content_type_based_on_url(url)
393 401 should "not login as the user" do
394 402 assert_equal User.anonymous, User.current
395 403 end
396 404 end
397 405 end
398 406
399 407 context "should allow key based auth using X-Redmine-API-Key header for #{http_method} #{url}" do
400 408 setup do
401 409 @user = User.generate! do |user|
402 410 user.admin = true
403 411 end
404 412 @token = Token.create!(:user => @user, :action => 'api')
405 413 send(http_method, url, parameters, {'X-Redmine-API-Key' => @token.value.to_s})
406 414 end
407 415 should_respond_with success_code
408 416 should_respond_with_content_type_based_on_url(url)
409 417 should_be_a_valid_response_string_based_on_url(url)
410 418 should "login as the user" do
411 419 assert_equal @user, User.current
412 420 end
413 421 end
414 422 end
415 423
416 424 # Uses should_respond_with_content_type based on what's in the url:
417 425 #
418 426 # '/project/issues.xml' => should_respond_with_content_type :xml
419 427 # '/project/issues.json' => should_respond_with_content_type :json
420 428 #
421 429 # @param [String] url Request
422 430 def self.should_respond_with_content_type_based_on_url(url)
423 431 case
424 432 when url.match(/xml/i)
425 433 should "respond with XML" do
426 434 assert_equal 'application/xml', @response.content_type
427 435 end
428 436 when url.match(/json/i)
429 437 should "respond with JSON" do
430 438 assert_equal 'application/json', @response.content_type
431 439 end
432 440 else
433 441 raise "Unknown content type for should_respond_with_content_type_based_on_url: #{url}"
434 442 end
435 443 end
436 444
437 445 # Uses the url to assert which format the response should be in
438 446 #
439 447 # '/project/issues.xml' => should_be_a_valid_xml_string
440 448 # '/project/issues.json' => should_be_a_valid_json_string
441 449 #
442 450 # @param [String] url Request
443 451 def self.should_be_a_valid_response_string_based_on_url(url)
444 452 case
445 453 when url.match(/xml/i)
446 454 should_be_a_valid_xml_string
447 455 when url.match(/json/i)
448 456 should_be_a_valid_json_string
449 457 else
450 458 raise "Unknown content type for should_be_a_valid_response_based_on_url: #{url}"
451 459 end
452 460 end
453 461
454 462 # Checks that the response is a valid JSON string
455 463 def self.should_be_a_valid_json_string
456 464 should "be a valid JSON string (or empty)" do
457 465 assert(response.body.blank? || ActiveSupport::JSON.decode(response.body))
458 466 end
459 467 end
460 468
461 469 # Checks that the response is a valid XML string
462 470 def self.should_be_a_valid_xml_string
463 471 should "be a valid XML string" do
464 472 assert REXML::Document.new(response.body)
465 473 end
466 474 end
467 475
468 476 def self.should_respond_with(status)
469 477 should "respond with #{status}" do
470 478 assert_response status
471 479 end
472 480 end
473 481 end
474 482 end
475 483 end
476 484
477 485 # URL helpers do not work with config.threadsafe!
478 486 # https://github.com/rspec/rspec-rails/issues/476#issuecomment-4705454
479 487 ActionView::TestCase::TestController.instance_eval do
480 488 helper Rails.application.routes.url_helpers
481 489 end
482 490 ActionView::TestCase::TestController.class_eval do
483 491 def _routes
484 492 Rails.application.routes
485 493 end
486 494 end
@@ -1,39 +1,53
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2014 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 QueriesHelperTest < ActionView::TestCase
21 21 include QueriesHelper
22 22 include Redmine::I18n
23 23
24 24 fixtures :projects, :enabled_modules, :users, :members,
25 25 :member_roles, :roles, :trackers, :issue_statuses,
26 26 :issue_categories, :enumerations, :issues,
27 27 :watchers, :custom_fields, :custom_values, :versions,
28 28 :queries,
29 29 :projects_trackers,
30 30 :custom_fields_trackers
31 31
32 32 def test_filters_options_has_empty_item
33 33 query = IssueQuery.new
34 34 filter_count = query.available_filters.size
35 35 fo = filters_options(query)
36 36 assert_equal filter_count + 1, fo.size
37 37 assert_equal [], fo[0]
38 38 end
39
40 def test_query_to_csv_should_translate_boolean_custom_field_values
41 f = IssueCustomField.generate!(:field_format => 'bool', :name => 'Boolean', :is_for_all => true, :trackers => Tracker.all)
42 issues = [
43 Issue.generate!(:project_id => 1, :tracker_id => 1, :custom_field_values => {f.id.to_s => '0'}),
44 Issue.generate!(:project_id => 1, :tracker_id => 1, :custom_field_values => {f.id.to_s => '1'})
45 ]
46
47 with_locale 'fr' do
48 csv = query_to_csv(issues, IssueQuery.new, :columns => 'all')
49 assert_include "Oui", csv
50 assert_include "Non", csv
51 end
52 end
39 53 end
General Comments 0
You need to be logged in to leave comments. Login now