##// END OF EJS Templates
Merged r12896 (#16081)....
Jean-Philippe Lang -
r12671:d05cbf4df846
parent child
Show More
@@ -1,224 +1,228
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)) + " #{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 value.class.name
94 94 when 'String'
95 95 if column.name == :subject
96 96 link_to(h(value), :controller => 'issues', :action => 'show', :id => issue)
97 97 elsif column.name == :description
98 98 issue.description? ? content_tag('div', textilizable(issue, :description), :class => "wiki") : ''
99 99 else
100 100 h(value)
101 101 end
102 102 when 'Time'
103 103 format_time(value)
104 104 when 'Date'
105 105 format_date(value)
106 106 when 'Fixnum'
107 107 if column.name == :id
108 108 link_to value, issue_path(issue)
109 109 elsif column.name == :done_ratio
110 110 progress_bar(value, :width => '80px')
111 111 else
112 112 value.to_s
113 113 end
114 114 when 'Float'
115 115 sprintf "%.2f", value
116 116 when 'User'
117 117 link_to_user value
118 118 when 'Project'
119 119 link_to_project value
120 120 when 'Version'
121 121 link_to(h(value), :controller => 'versions', :action => 'show', :id => value)
122 122 when 'TrueClass'
123 123 l(:general_text_Yes)
124 124 when 'FalseClass'
125 125 l(:general_text_No)
126 126 when 'Issue'
127 127 value.visible? ? link_to_issue(value) : "##{value.id}"
128 128 when 'IssueRelation'
129 129 other = value.other_issue(issue)
130 130 content_tag('span',
131 131 (l(value.label_for(issue)) + " " + link_to_issue(other, :subject => false, :tracker => false)).html_safe,
132 132 :class => value.css_classes_for(issue))
133 133 else
134 134 h(value)
135 135 end
136 136 end
137 137
138 138 def csv_content(column, issue)
139 139 value = column.value(issue)
140 140 if value.is_a?(Array)
141 141 value.collect {|v| csv_value(column, issue, v)}.compact.join(', ')
142 142 else
143 143 csv_value(column, issue, value)
144 144 end
145 145 end
146 146
147 147 def csv_value(column, issue, value)
148 148 case value.class.name
149 149 when 'Time'
150 150 format_time(value)
151 151 when 'Date'
152 152 format_date(value)
153 153 when 'Float'
154 154 sprintf("%.2f", value).gsub('.', l(:general_csv_decimal_separator))
155 155 when 'IssueRelation'
156 156 other = value.other_issue(issue)
157 157 l(value.label_for(issue)) + " ##{other.id}"
158 when 'TrueClass'
159 l(:general_text_Yes)
160 when 'FalseClass'
161 l(:general_text_No)
158 162 else
159 163 value.to_s
160 164 end
161 165 end
162 166
163 167 def query_to_csv(items, query, options={})
164 168 encoding = l(:general_csv_encoding)
165 169 columns = (options[:columns] == 'all' ? query.available_inline_columns : query.inline_columns)
166 170 query.available_block_columns.each do |column|
167 171 if options[column.name].present?
168 172 columns << column
169 173 end
170 174 end
171 175
172 176 export = FCSV.generate(:col_sep => l(:general_csv_separator)) do |csv|
173 177 # csv header fields
174 178 csv << columns.collect {|c| Redmine::CodesetUtil.from_utf8(c.caption.to_s, encoding) }
175 179 # csv lines
176 180 items.each do |item|
177 181 csv << columns.collect {|c| Redmine::CodesetUtil.from_utf8(csv_content(c, item), encoding) }
178 182 end
179 183 end
180 184 export
181 185 end
182 186
183 187 # Retrieve query from session or build a new query
184 188 def retrieve_query
185 189 if !params[:query_id].blank?
186 190 cond = "project_id IS NULL"
187 191 cond << " OR project_id = #{@project.id}" if @project
188 192 @query = IssueQuery.where(cond).find(params[:query_id])
189 193 raise ::Unauthorized unless @query.visible?
190 194 @query.project = @project
191 195 session[:query] = {:id => @query.id, :project_id => @query.project_id}
192 196 sort_clear
193 197 elsif api_request? || params[:set_filter] || session[:query].nil? || session[:query][:project_id] != (@project ? @project.id : nil)
194 198 # Give it a name, required to be valid
195 199 @query = IssueQuery.new(:name => "_")
196 200 @query.project = @project
197 201 @query.build_from_params(params)
198 202 session[:query] = {:project_id => @query.project_id, :filters => @query.filters, :group_by => @query.group_by, :column_names => @query.column_names}
199 203 else
200 204 # retrieve from session
201 205 @query = nil
202 206 @query = IssueQuery.find_by_id(session[:query][:id]) if session[:query][:id]
203 207 @query ||= IssueQuery.new(:name => "_", :filters => session[:query][:filters], :group_by => session[:query][:group_by], :column_names => session[:query][:column_names])
204 208 @query.project = @project
205 209 end
206 210 end
207 211
208 212 def retrieve_query_from_session
209 213 if session[:query]
210 214 if session[:query][:id]
211 215 @query = IssueQuery.find_by_id(session[:query][:id])
212 216 return unless @query
213 217 else
214 218 @query = IssueQuery.new(:name => "_", :filters => session[:query][:filters], :group_by => session[:query][:group_by], :column_names => session[:query][:column_names])
215 219 end
216 220 if session[:query].has_key?(:project_id)
217 221 @query.project_id = session[:query][:project_id]
218 222 else
219 223 @query.project = @project
220 224 end
221 225 @query
222 226 end
223 227 end
224 228 end
@@ -1,468 +1,476
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 class ActiveSupport::TestCase
28 28 include ActionDispatch::TestProcess
29 29
30 30 self.use_transactional_fixtures = true
31 31 self.use_instantiated_fixtures = false
32 32
33 33 def log_user(login, password)
34 34 User.anonymous
35 35 get "/login"
36 36 assert_equal nil, session[:user_id]
37 37 assert_response :success
38 38 assert_template "account/login"
39 39 post "/login", :username => login, :password => password
40 40 assert_equal login, User.find(session[:user_id]).login
41 41 end
42 42
43 43 def uploaded_test_file(name, mime)
44 44 fixture_file_upload("files/#{name}", mime, true)
45 45 end
46 46
47 47 def credentials(user, password=nil)
48 48 {'HTTP_AUTHORIZATION' => ActionController::HttpAuthentication::Basic.encode_credentials(user, password || user)}
49 49 end
50 50
51 51 # Mock out a file
52 52 def self.mock_file
53 53 file = 'a_file.png'
54 54 file.stubs(:size).returns(32)
55 55 file.stubs(:original_filename).returns('a_file.png')
56 56 file.stubs(:content_type).returns('image/png')
57 57 file.stubs(:read).returns(false)
58 58 file
59 59 end
60 60
61 61 def mock_file
62 62 self.class.mock_file
63 63 end
64 64
65 65 def mock_file_with_options(options={})
66 66 file = ''
67 67 file.stubs(:size).returns(32)
68 68 original_filename = options[:original_filename] || nil
69 69 file.stubs(:original_filename).returns(original_filename)
70 70 content_type = options[:content_type] || nil
71 71 file.stubs(:content_type).returns(content_type)
72 72 file.stubs(:read).returns(false)
73 73 file
74 74 end
75 75
76 76 # Use a temporary directory for attachment related tests
77 77 def set_tmp_attachments_directory
78 78 Dir.mkdir "#{Rails.root}/tmp/test" unless File.directory?("#{Rails.root}/tmp/test")
79 79 unless File.directory?("#{Rails.root}/tmp/test/attachments")
80 80 Dir.mkdir "#{Rails.root}/tmp/test/attachments"
81 81 end
82 82 Attachment.storage_path = "#{Rails.root}/tmp/test/attachments"
83 83 end
84 84
85 85 def set_fixtures_attachments_directory
86 86 Attachment.storage_path = "#{Rails.root}/test/fixtures/files"
87 87 end
88 88
89 89 def with_settings(options, &block)
90 90 saved_settings = options.keys.inject({}) do |h, k|
91 91 h[k] = case Setting[k]
92 92 when Symbol, false, true, nil
93 93 Setting[k]
94 94 else
95 95 Setting[k].dup
96 96 end
97 97 h
98 98 end
99 99 options.each {|k, v| Setting[k] = v}
100 100 yield
101 101 ensure
102 102 saved_settings.each {|k, v| Setting[k] = v} if saved_settings
103 103 end
104 104
105 105 # Yields the block with user as the current user
106 106 def with_current_user(user, &block)
107 107 saved_user = User.current
108 108 User.current = user
109 109 yield
110 110 ensure
111 111 User.current = saved_user
112 112 end
113 113
114 def with_locale(locale, &block)
115 saved_localed = ::I18n.locale
116 ::I18n.locale = locale
117 yield
118 ensure
119 ::I18n.locale = saved_localed
120 end
121
114 122 def change_user_password(login, new_password)
115 123 user = User.where(:login => login).first
116 124 user.password, user.password_confirmation = new_password, new_password
117 125 user.save!
118 126 end
119 127
120 128 def self.ldap_configured?
121 129 @test_ldap = Net::LDAP.new(:host => '127.0.0.1', :port => 389)
122 130 return @test_ldap.bind
123 131 rescue Exception => e
124 132 # LDAP is not listening
125 133 return nil
126 134 end
127 135
128 136 def self.convert_installed?
129 137 Redmine::Thumbnail.convert_available?
130 138 end
131 139
132 140 # Returns the path to the test +vendor+ repository
133 141 def self.repository_path(vendor)
134 142 Rails.root.join("tmp/test/#{vendor.downcase}_repository").to_s
135 143 end
136 144
137 145 # Returns the url of the subversion test repository
138 146 def self.subversion_repository_url
139 147 path = repository_path('subversion')
140 148 path = '/' + path unless path.starts_with?('/')
141 149 "file://#{path}"
142 150 end
143 151
144 152 # Returns true if the +vendor+ test repository is configured
145 153 def self.repository_configured?(vendor)
146 154 File.directory?(repository_path(vendor))
147 155 end
148 156
149 157 def repository_path_hash(arr)
150 158 hs = {}
151 159 hs[:path] = arr.join("/")
152 160 hs[:param] = arr.join("/")
153 161 hs
154 162 end
155 163
156 164 def assert_save(object)
157 165 saved = object.save
158 166 message = "#{object.class} could not be saved"
159 167 errors = object.errors.full_messages.map {|m| "- #{m}"}
160 168 message << ":\n#{errors.join("\n")}" if errors.any?
161 169 assert_equal true, saved, message
162 170 end
163 171
164 172 def assert_error_tag(options={})
165 173 assert_tag({:attributes => { :id => 'errorExplanation' }}.merge(options))
166 174 end
167 175
168 176 def assert_include(expected, s, message=nil)
169 177 assert s.include?(expected), (message || "\"#{expected}\" not found in \"#{s}\"")
170 178 end
171 179
172 180 def assert_not_include(expected, s, message=nil)
173 181 assert !s.include?(expected), (message || "\"#{expected}\" found in \"#{s}\"")
174 182 end
175 183
176 184 def assert_select_in(text, *args, &block)
177 185 d = HTML::Document.new(CGI::unescapeHTML(String.new(text))).root
178 186 assert_select(d, *args, &block)
179 187 end
180 188
181 189 def assert_mail_body_match(expected, mail, message=nil)
182 190 if expected.is_a?(String)
183 191 assert_include expected, mail_body(mail), message
184 192 else
185 193 assert_match expected, mail_body(mail), message
186 194 end
187 195 end
188 196
189 197 def assert_mail_body_no_match(expected, mail, message=nil)
190 198 if expected.is_a?(String)
191 199 assert_not_include expected, mail_body(mail), message
192 200 else
193 201 assert_no_match expected, mail_body(mail), message
194 202 end
195 203 end
196 204
197 205 def mail_body(mail)
198 206 mail.parts.first.body.encoded
199 207 end
200 208 end
201 209
202 210 module Redmine
203 211 module ApiTest
204 212 # Base class for API tests
205 213 class Base < ActionDispatch::IntegrationTest
206 214 # Test that a request allows the three types of API authentication
207 215 #
208 216 # * HTTP Basic with username and password
209 217 # * HTTP Basic with an api key for the username
210 218 # * Key based with the key=X parameter
211 219 #
212 220 # @param [Symbol] http_method the HTTP method for request (:get, :post, :put, :delete)
213 221 # @param [String] url the request url
214 222 # @param [optional, Hash] parameters additional request parameters
215 223 # @param [optional, Hash] options additional options
216 224 # @option options [Symbol] :success_code Successful response code (:success)
217 225 # @option options [Symbol] :failure_code Failure response code (:unauthorized)
218 226 def self.should_allow_api_authentication(http_method, url, parameters={}, options={})
219 227 should_allow_http_basic_auth_with_username_and_password(http_method, url, parameters, options)
220 228 should_allow_http_basic_auth_with_key(http_method, url, parameters, options)
221 229 should_allow_key_based_auth(http_method, url, parameters, options)
222 230 end
223 231
224 232 # Test that a request allows the username and password for HTTP BASIC
225 233 #
226 234 # @param [Symbol] http_method the HTTP method for request (:get, :post, :put, :delete)
227 235 # @param [String] url the request url
228 236 # @param [optional, Hash] parameters additional request parameters
229 237 # @param [optional, Hash] options additional options
230 238 # @option options [Symbol] :success_code Successful response code (:success)
231 239 # @option options [Symbol] :failure_code Failure response code (:unauthorized)
232 240 def self.should_allow_http_basic_auth_with_username_and_password(http_method, url, parameters={}, options={})
233 241 success_code = options[:success_code] || :success
234 242 failure_code = options[:failure_code] || :unauthorized
235 243
236 244 context "should allow http basic auth using a username and password for #{http_method} #{url}" do
237 245 context "with a valid HTTP authentication" do
238 246 setup do
239 247 @user = User.generate! do |user|
240 248 user.admin = true
241 249 user.password = 'my_password'
242 250 end
243 251 send(http_method, url, parameters, credentials(@user.login, 'my_password'))
244 252 end
245 253
246 254 should_respond_with success_code
247 255 should_respond_with_content_type_based_on_url(url)
248 256 should "login as the user" do
249 257 assert_equal @user, User.current
250 258 end
251 259 end
252 260
253 261 context "with an invalid HTTP authentication" do
254 262 setup do
255 263 @user = User.generate!
256 264 send(http_method, url, parameters, credentials(@user.login, 'wrong_password'))
257 265 end
258 266
259 267 should_respond_with failure_code
260 268 should_respond_with_content_type_based_on_url(url)
261 269 should "not login as the user" do
262 270 assert_equal User.anonymous, User.current
263 271 end
264 272 end
265 273
266 274 context "without credentials" do
267 275 setup do
268 276 send(http_method, url, parameters)
269 277 end
270 278
271 279 should_respond_with failure_code
272 280 should_respond_with_content_type_based_on_url(url)
273 281 should "include_www_authenticate_header" do
274 282 assert @controller.response.headers.has_key?('WWW-Authenticate')
275 283 end
276 284 end
277 285 end
278 286 end
279 287
280 288 # Test that a request allows the API key with HTTP BASIC
281 289 #
282 290 # @param [Symbol] http_method the HTTP method for request (:get, :post, :put, :delete)
283 291 # @param [String] url the request url
284 292 # @param [optional, Hash] parameters additional request parameters
285 293 # @param [optional, Hash] options additional options
286 294 # @option options [Symbol] :success_code Successful response code (:success)
287 295 # @option options [Symbol] :failure_code Failure response code (:unauthorized)
288 296 def self.should_allow_http_basic_auth_with_key(http_method, url, parameters={}, options={})
289 297 success_code = options[:success_code] || :success
290 298 failure_code = options[:failure_code] || :unauthorized
291 299
292 300 context "should allow http basic auth with a key for #{http_method} #{url}" do
293 301 context "with a valid HTTP authentication using the API token" do
294 302 setup do
295 303 @user = User.generate! do |user|
296 304 user.admin = true
297 305 end
298 306 @token = Token.create!(:user => @user, :action => 'api')
299 307 send(http_method, url, parameters, credentials(@token.value, 'X'))
300 308 end
301 309 should_respond_with success_code
302 310 should_respond_with_content_type_based_on_url(url)
303 311 should_be_a_valid_response_string_based_on_url(url)
304 312 should "login as the user" do
305 313 assert_equal @user, User.current
306 314 end
307 315 end
308 316
309 317 context "with an invalid HTTP authentication" do
310 318 setup do
311 319 @user = User.generate!
312 320 @token = Token.create!(:user => @user, :action => 'feeds')
313 321 send(http_method, url, parameters, credentials(@token.value, 'X'))
314 322 end
315 323 should_respond_with failure_code
316 324 should_respond_with_content_type_based_on_url(url)
317 325 should "not login as the user" do
318 326 assert_equal User.anonymous, User.current
319 327 end
320 328 end
321 329 end
322 330 end
323 331
324 332 # Test that a request allows full key authentication
325 333 #
326 334 # @param [Symbol] http_method the HTTP method for request (:get, :post, :put, :delete)
327 335 # @param [String] url the request url, without the key=ZXY parameter
328 336 # @param [optional, Hash] parameters additional request parameters
329 337 # @param [optional, Hash] options additional options
330 338 # @option options [Symbol] :success_code Successful response code (:success)
331 339 # @option options [Symbol] :failure_code Failure response code (:unauthorized)
332 340 def self.should_allow_key_based_auth(http_method, url, parameters={}, options={})
333 341 success_code = options[:success_code] || :success
334 342 failure_code = options[:failure_code] || :unauthorized
335 343
336 344 context "should allow key based auth using key=X for #{http_method} #{url}" do
337 345 context "with a valid api token" do
338 346 setup do
339 347 @user = User.generate! do |user|
340 348 user.admin = true
341 349 end
342 350 @token = Token.create!(:user => @user, :action => 'api')
343 351 # Simple url parse to add on ?key= or &key=
344 352 request_url = if url.match(/\?/)
345 353 url + "&key=#{@token.value}"
346 354 else
347 355 url + "?key=#{@token.value}"
348 356 end
349 357 send(http_method, request_url, parameters)
350 358 end
351 359 should_respond_with success_code
352 360 should_respond_with_content_type_based_on_url(url)
353 361 should_be_a_valid_response_string_based_on_url(url)
354 362 should "login as the user" do
355 363 assert_equal @user, User.current
356 364 end
357 365 end
358 366
359 367 context "with an invalid api token" do
360 368 setup do
361 369 @user = User.generate! do |user|
362 370 user.admin = true
363 371 end
364 372 @token = Token.create!(:user => @user, :action => 'feeds')
365 373 # Simple url parse to add on ?key= or &key=
366 374 request_url = if url.match(/\?/)
367 375 url + "&key=#{@token.value}"
368 376 else
369 377 url + "?key=#{@token.value}"
370 378 end
371 379 send(http_method, request_url, parameters)
372 380 end
373 381 should_respond_with failure_code
374 382 should_respond_with_content_type_based_on_url(url)
375 383 should "not login as the user" do
376 384 assert_equal User.anonymous, User.current
377 385 end
378 386 end
379 387 end
380 388
381 389 context "should allow key based auth using X-Redmine-API-Key header for #{http_method} #{url}" do
382 390 setup do
383 391 @user = User.generate! do |user|
384 392 user.admin = true
385 393 end
386 394 @token = Token.create!(:user => @user, :action => 'api')
387 395 send(http_method, url, parameters, {'X-Redmine-API-Key' => @token.value.to_s})
388 396 end
389 397 should_respond_with success_code
390 398 should_respond_with_content_type_based_on_url(url)
391 399 should_be_a_valid_response_string_based_on_url(url)
392 400 should "login as the user" do
393 401 assert_equal @user, User.current
394 402 end
395 403 end
396 404 end
397 405
398 406 # Uses should_respond_with_content_type based on what's in the url:
399 407 #
400 408 # '/project/issues.xml' => should_respond_with_content_type :xml
401 409 # '/project/issues.json' => should_respond_with_content_type :json
402 410 #
403 411 # @param [String] url Request
404 412 def self.should_respond_with_content_type_based_on_url(url)
405 413 case
406 414 when url.match(/xml/i)
407 415 should "respond with XML" do
408 416 assert_equal 'application/xml', @response.content_type
409 417 end
410 418 when url.match(/json/i)
411 419 should "respond with JSON" do
412 420 assert_equal 'application/json', @response.content_type
413 421 end
414 422 else
415 423 raise "Unknown content type for should_respond_with_content_type_based_on_url: #{url}"
416 424 end
417 425 end
418 426
419 427 # Uses the url to assert which format the response should be in
420 428 #
421 429 # '/project/issues.xml' => should_be_a_valid_xml_string
422 430 # '/project/issues.json' => should_be_a_valid_json_string
423 431 #
424 432 # @param [String] url Request
425 433 def self.should_be_a_valid_response_string_based_on_url(url)
426 434 case
427 435 when url.match(/xml/i)
428 436 should_be_a_valid_xml_string
429 437 when url.match(/json/i)
430 438 should_be_a_valid_json_string
431 439 else
432 440 raise "Unknown content type for should_be_a_valid_response_based_on_url: #{url}"
433 441 end
434 442 end
435 443
436 444 # Checks that the response is a valid JSON string
437 445 def self.should_be_a_valid_json_string
438 446 should "be a valid JSON string (or empty)" do
439 447 assert(response.body.blank? || ActiveSupport::JSON.decode(response.body))
440 448 end
441 449 end
442 450
443 451 # Checks that the response is a valid XML string
444 452 def self.should_be_a_valid_xml_string
445 453 should "be a valid XML string" do
446 454 assert REXML::Document.new(response.body)
447 455 end
448 456 end
449 457
450 458 def self.should_respond_with(status)
451 459 should "respond with #{status}" do
452 460 assert_response status
453 461 end
454 462 end
455 463 end
456 464 end
457 465 end
458 466
459 467 # URL helpers do not work with config.threadsafe!
460 468 # https://github.com/rspec/rspec-rails/issues/476#issuecomment-4705454
461 469 ActionView::TestCase::TestController.instance_eval do
462 470 helper Rails.application.routes.url_helpers
463 471 end
464 472 ActionView::TestCase::TestController.class_eval do
465 473 def _routes
466 474 Rails.application.routes
467 475 end
468 476 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