lib/action_controller/test_process.rb in actionpack-2.1.2 vs lib/action_controller/test_process.rb in actionpack-2.2.2

- old
+ new

@@ -1,10 +1,12 @@ require 'action_controller/assertions' require 'action_controller/test_case' module ActionController #:nodoc: class Base + attr_reader :assigns + # Process a test request called with a TestRequest object. def self.process_test(request) new.process_test(request) end @@ -12,20 +14,25 @@ process(request, TestResponse.new) end def process_with_test(*args) returning process_without_test(*args) do - add_variables_to_assigns + @assigns = {} + (instance_variable_names - @@protected_instance_variables).each do |var| + value = instance_variable_get(var) + @assigns[var[1..-1]] = value + response.template.assigns[var[1..-1]] = value if response + end end end alias_method_chain :process, :test end class TestRequest < AbstractRequest #:nodoc: attr_accessor :cookies, :session_options - attr_accessor :query_parameters, :request_parameters, :path, :session, :env + attr_accessor :query_parameters, :request_parameters, :path, :session attr_accessor :host, :user_agent def initialize(query_parameters = nil, request_parameters = nil, session = nil) @query_parameters = query_parameters || {} @request_parameters = request_parameters || {} @@ -40,11 +47,11 @@ def reset_session @session = TestSession.new end # Wraps raw_post in a StringIO. - def body + def body_stream #:nodoc: StringIO.new(raw_post) end # Either the RAW_POST_DATA environment variable or the URL-encoded request # parameters. @@ -52,11 +59,11 @@ env['RAW_POST_DATA'] ||= returning(url_encoded_request_parameters) { |b| b.force_encoding(Encoding::BINARY) if b.respond_to?(:force_encoding) } end def port=(number) @env["SERVER_PORT"] = number.to_i - @port_as_int = nil + port(true) end def action=(action_name) @query_parameters.update({ "action" => action_name }) @parameters = nil @@ -66,34 +73,41 @@ # Disables the use of @path and @request_uri so superclass can handle those. def set_REQUEST_URI(value) @env["REQUEST_URI"] = value @request_uri = nil @path = nil + request_uri(true) + path(true) end def request_uri=(uri) @request_uri = uri @path = uri.split("?").first end def accept=(mime_types) @env["HTTP_ACCEPT"] = Array(mime_types).collect { |mime_types| mime_types.to_s }.join(",") + accepts(true) end - def remote_addr=(addr) - @env['REMOTE_ADDR'] = addr + def if_modified_since=(last_modified) + @env["HTTP_IF_MODIFIED_SINCE"] = last_modified end - def remote_addr - @env['REMOTE_ADDR'] + def if_none_match=(etag) + @env["HTTP_IF_NONE_MATCH"] = etag end - def request_uri + def remote_addr=(addr) + @env['REMOTE_ADDR'] = addr + end + + def request_uri(*args) @request_uri || super end - def path + def path(*args) @path || super end def assign_parameters(controller_path, action, parameters) parameters = parameters.symbolize_keys.merge(:controller => controller_path, :action => action) @@ -111,21 +125,17 @@ else path_parameters[key.to_s] = value end end @parameters = nil # reset TestRequest#parameters to use the new path_parameters - end - + end + def recycle! self.request_parameters = {} self.query_parameters = {} self.path_parameters = {} - @request_method, @accepts, @content_type = nil, nil, nil - end - - def referer - @env["HTTP_REFERER"] + unmemoize_all end private def initialize_containers @env, @cookies = {}, {} @@ -133,11 +143,11 @@ def initialize_default_values @host = "test.host" @request_uri = "/" @user_agent = "Rails Testing" - self.remote_addr = "0.0.0.0" + self.remote_addr = "0.0.0.0" @env["SERVER_PORT"] = 80 @env['REQUEST_METHOD'] = "GET" end def url_encoded_request_parameters @@ -155,20 +165,20 @@ # A refactoring of TestResponse to allow the same behavior to be applied # to the "real" CgiResponse class in integration tests. module TestResponseBehavior #:nodoc: # The response code of the request def response_code - headers['Status'][0,3].to_i rescue 0 + status[0,3].to_i rescue 0 end - + # Returns a String to ensure compatibility with Net::HTTPResponse def code - headers['Status'].to_s.split(' ')[0] + status.to_s.split(' ')[0] end def message - headers['Status'].to_s.split(' ',2)[1] + status.to_s.split(' ',2)[1] end # Was the response successful? def success? (200..299).include?(response_code) @@ -203,28 +213,17 @@ p = pattern if pattern.class == Regexp return false if p.nil? p.match(redirect_url) != nil end - # Returns the template path of the file which was used to - # render this response (or nil) - def rendered_file(with_controller=false) - unless template.first_render.nil? - unless with_controller - template.first_render - else - template.first_render.split('/').last || template.first_render - end - end + # Returns the template of the file which was used to + # render this response (or nil) + def rendered_template + template.instance_variable_get(:@_first_render) end - # Was this template rendered by a file? - def rendered_with_file? - !rendered_file.nil? - end - - # A shortcut to the flash. Returns an empyt hash if no session flash exists. + # A shortcut to the flash. Returns an empty hash if no session flash exists. def flash session['flash'] || {} end # Do we have a flash? @@ -252,15 +251,15 @@ template.assigns || {} end # Does the specified template object exist? def has_template_object?(name=nil) - !template_objects[name].nil? + !template_objects[name].nil? end # Returns the response cookies, converted to a Hash of (name => CGI::Cookie) pairs - # + # # assert_equal ['AuthorOfNewPage'], r.cookies['author'].value def cookies headers['cookie'].inject({}) { |hash, cookie| hash[cookie.name] = cookie; hash } end @@ -275,12 +274,23 @@ sio.rewind sio.read end end - class TestResponse < AbstractResponse #:nodoc: + # Integration test methods such as ActionController::Integration::Session#get + # and ActionController::Integration::Session#post return objects of class + # TestResponse, which represent the HTTP response results of the requested + # controller actions. + # + # See AbstractResponse for more information on controller response objects. + class TestResponse < AbstractResponse include TestResponseBehavior + + def recycle! + headers.delete('ETag') + headers.delete('Last-Modified') + end end class TestSession #:nodoc: attr_accessor :session_id @@ -322,11 +332,11 @@ # object in the params of a test request in order to simulate # a file upload. # # Usage example, within a functional test: # post :change_avatar, :avatar => ActionController::TestUploadedFile.new(Test::Unit::TestCase.fixture_path + '/files/spongebob.png', 'image/png') - # + # # Pass a true third parameter to ensure the uploaded file is opened in binary mode (only required for Windows): # post :change_avatar, :avatar => ActionController::TestUploadedFile.new(Test::Unit::TestCase.fixture_path + '/files/spongebob.png', 'image/png', :binary) require 'tempfile' class TestUploadedFile # The filename, *not* including the path, of the "uploaded" file @@ -350,17 +360,18 @@ end alias local_path path def method_missing(method_name, *args, &block) #:nodoc: - @tempfile.send!(method_name, *args, &block) + @tempfile.__send__(method_name, *args, &block) end end module TestProcess def self.included(base) # execute the request simulating a specific HTTP method and set/volley the response + # TODO: this should be un-DRY'ed for the sake of API documentation. %w( get post put delete head ).each do |method| base.class_eval <<-EOV, __FILE__, __LINE__ def #{method}(action, parameters = nil, session = nil, flash = nil) @request.env['REQUEST_METHOD'] = "#{method.upcase}" if defined?(@request) process(action, parameters, session, flash) @@ -378,13 +389,15 @@ raise "#{iv_name} is nil: make sure you set it in your test's setup method." end end @request.recycle! + @response.recycle! @html_document = nil @request.env['REQUEST_METHOD'] ||= "GET" + @request.action = action.to_s parameters ||= {} @request.assign_parameters(@controller.class.controller_path, action.to_s, parameters) @@ -395,36 +408,25 @@ end def xml_http_request(request_method, action, parameters = nil, session = nil, flash = nil) @request.env['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest' @request.env['HTTP_ACCEPT'] = 'text/javascript, text/html, application/xml, text/xml, */*' - returning send!(request_method, action, parameters, session, flash) do + returning __send__(request_method, action, parameters, session, flash) do @request.env.delete 'HTTP_X_REQUESTED_WITH' @request.env.delete 'HTTP_ACCEPT' end end alias xhr :xml_http_request - def follow_redirect - redirected_controller = @response.redirected_to[:controller] - if redirected_controller && redirected_controller != @controller.controller_name - raise "Can't follow redirects outside of current controller (from #{@controller.controller_name} to #{redirected_controller})" + def assigns(key = nil) + if key.nil? + @response.template.assigns + else + @response.template.assigns[key.to_s] end - - get(@response.redirected_to.delete(:action), @response.redirected_to.stringify_keys) end - deprecate :follow_redirect => "If you wish to follow redirects, you should use integration tests" - - def assigns(key = nil) - if key.nil? - @response.template.assigns - else - @response.template.assigns[key.to_s] - end - end - def session @response.session end def flash @@ -439,11 +441,11 @@ @response.redirect_url end def build_request_uri(action, parameters) unless @request.env['REQUEST_URI'] - options = @controller.send!(:rewrite_options, parameters) + options = @controller.__send__(:rewrite_options, parameters) options.update(:only_path => true, :action => action) url = ActionController::UrlRewriter.new(@request, parameters) @request.set_REQUEST_URI(url.rewrite(options)) end @@ -461,32 +463,35 @@ def find_all_tag(conditions) html_document.find_all(conditions) end def method_missing(selector, *args) - return @controller.send!(selector, *args) if ActionController::Routing::Routes.named_routes.helpers.include?(selector) - return super + if ActionController::Routing::Routes.named_routes.helpers.include?(selector) + @controller.send(selector, *args) + else + super + end end - + # Shortcut for <tt>ActionController::TestUploadedFile.new(Test::Unit::TestCase.fixture_path + path, type)</tt>: # # post :change_avatar, :avatar => fixture_file_upload('/files/spongebob.png', 'image/png') # # To upload binary files on Windows, pass <tt>:binary</tt> as the last parameter. # This will not affect other platforms: # # post :change_avatar, :avatar => fixture_file_upload('/files/spongebob.png', 'image/png', :binary) def fixture_file_upload(path, mime_type = nil, binary = false) ActionController::TestUploadedFile.new( - Test::Unit::TestCase.respond_to?(:fixture_path) ? Test::Unit::TestCase.fixture_path + path : path, + Test::Unit::TestCase.respond_to?(:fixture_path) ? Test::Unit::TestCase.fixture_path + path : path, mime_type, binary ) end # A helper to make it easier to test different route configurations. # This method temporarily replaces ActionController::Routing::Routes - # with a new RouteSet instance. + # with a new RouteSet instance. # # The new instance is yielded to the passed block. Typically the block # will create some routes using <tt>map.draw { map.connect ... }</tt>: # # with_routing do |set|