summary refs log tree commit
path: root/lib/rack/mock.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/rack/mock.rb')
-rw-r--r--lib/rack/mock.rb285
1 files changed, 1 insertions, 284 deletions
diff --git a/lib/rack/mock.rb b/lib/rack/mock.rb
index c048e302..5e5c457c 100644
--- a/lib/rack/mock.rb
+++ b/lib/rack/mock.rb
@@ -1,286 +1,3 @@
 # frozen_string_literal: true
 
-require 'uri'
-require 'stringio'
-require 'cgi/cookie'
-require 'time'
-
-require_relative 'response'
-require_relative 'version'
-require_relative 'constants'
-require_relative 'headers'
-
-module Rack
-  # Rack::MockRequest helps testing your Rack application without
-  # actually using HTTP.
-  #
-  # After performing a request on a URL with get/post/put/patch/delete, it
-  # returns a MockResponse with useful helper methods for effective
-  # testing.
-  #
-  # You can pass a hash with additional configuration to the
-  # get/post/put/patch/delete.
-  # <tt>:input</tt>:: A String or IO-like to be used as rack.input.
-  # <tt>:fatal</tt>:: Raise a FatalWarning if the app writes to rack.errors.
-  # <tt>:lint</tt>:: If true, wrap the application in a Rack::Lint.
-
-  class MockRequest
-    class FatalWarning < RuntimeError
-    end
-
-    class FatalWarner
-      def puts(warning)
-        raise FatalWarning, warning
-      end
-
-      def write(warning)
-        raise FatalWarning, warning
-      end
-
-      def flush
-      end
-
-      def string
-        ""
-      end
-    end
-
-    DEFAULT_ENV = {
-      RACK_INPUT        => StringIO.new,
-      RACK_ERRORS       => StringIO.new,
-    }.freeze
-
-    def initialize(app)
-      @app = app
-    end
-
-    # Make a GET request and return a MockResponse. See #request.
-    def get(uri, opts = {})     request(GET, uri, opts)     end
-    # Make a POST request and return a MockResponse. See #request.
-    def post(uri, opts = {})    request(POST, uri, opts)    end
-    # Make a PUT request and return a MockResponse. See #request.
-    def put(uri, opts = {})     request(PUT, uri, opts)     end
-    # Make a PATCH request and return a MockResponse. See #request.
-    def patch(uri, opts = {})   request(PATCH, uri, opts)   end
-    # Make a DELETE request and return a MockResponse. See #request.
-    def delete(uri, opts = {})  request(DELETE, uri, opts)  end
-    # Make a HEAD request and return a MockResponse. See #request.
-    def head(uri, opts = {})    request(HEAD, uri, opts)    end
-    # Make an OPTIONS request and return a MockResponse. See #request.
-    def options(uri, opts = {}) request(OPTIONS, uri, opts) end
-
-    # Make a request using the given request method for the given
-    # uri to the rack application and return a MockResponse.
-    # Options given are passed to MockRequest.env_for.
-    def request(method = GET, uri = "", opts = {})
-      env = self.class.env_for(uri, opts.merge(method: method))
-
-      if opts[:lint]
-        app = Rack::Lint.new(@app)
-      else
-        app = @app
-      end
-
-      errors = env[RACK_ERRORS]
-      status, headers, body = app.call(env)
-      MockResponse.new(status, headers, body, errors)
-    ensure
-      body.close if body.respond_to?(:close)
-    end
-
-    # For historical reasons, we're pinning to RFC 2396.
-    # URI::Parser = URI::RFC2396_Parser
-    def self.parse_uri_rfc2396(uri)
-      @parser ||= URI::Parser.new
-      @parser.parse(uri)
-    end
-
-    # Return the Rack environment used for a request to +uri+.
-    # All options that are strings are added to the returned environment.
-    # Options:
-    # :fatal :: Whether to raise an exception if request outputs to rack.errors
-    # :input :: The rack.input to set
-    # :http_version :: The SERVER_PROTOCOL to set
-    # :method :: The HTTP request method to use
-    # :params :: The params to use
-    # :script_name :: The SCRIPT_NAME to set
-    def self.env_for(uri = "", opts = {})
-      uri = parse_uri_rfc2396(uri)
-      uri.path = "/#{uri.path}" unless uri.path[0] == ?/
-
-      env = DEFAULT_ENV.dup
-
-      env[REQUEST_METHOD]  = (opts[:method] ? opts[:method].to_s.upcase : GET).b
-      env[SERVER_NAME]     = (uri.host || "example.org").b
-      env[SERVER_PORT]     = (uri.port ? uri.port.to_s : "80").b
-      env[SERVER_PROTOCOL] = opts[:http_version] || 'HTTP/1.1'
-      env[QUERY_STRING]    = (uri.query.to_s).b
-      env[PATH_INFO]       = (uri.path).b
-      env[RACK_URL_SCHEME] = (uri.scheme || "http").b
-      env[HTTPS]           = (env[RACK_URL_SCHEME] == "https" ? "on" : "off").b
-
-      env[SCRIPT_NAME] = opts[:script_name] || ""
-
-      if opts[:fatal]
-        env[RACK_ERRORS] = FatalWarner.new
-      else
-        env[RACK_ERRORS] = StringIO.new
-      end
-
-      if params = opts[:params]
-        if env[REQUEST_METHOD] == GET
-          params = Utils.parse_nested_query(params) if params.is_a?(String)
-          params.update(Utils.parse_nested_query(env[QUERY_STRING]))
-          env[QUERY_STRING] = Utils.build_nested_query(params)
-        elsif !opts.has_key?(:input)
-          opts["CONTENT_TYPE"] = "application/x-www-form-urlencoded"
-          if params.is_a?(Hash)
-            if data = Rack::Multipart.build_multipart(params)
-              opts[:input] = data
-              opts["CONTENT_LENGTH"] ||= data.length.to_s
-              opts["CONTENT_TYPE"] = "multipart/form-data; boundary=#{Rack::Multipart::MULTIPART_BOUNDARY}"
-            else
-              opts[:input] = Utils.build_nested_query(params)
-            end
-          else
-            opts[:input] = params
-          end
-        end
-      end
-
-      opts[:input] ||= String.new
-      if String === opts[:input]
-        rack_input = StringIO.new(opts[:input])
-      else
-        rack_input = opts[:input]
-      end
-
-      rack_input.set_encoding(Encoding::BINARY)
-      env[RACK_INPUT] = rack_input
-
-      env["CONTENT_LENGTH"] ||= env[RACK_INPUT].size.to_s if env[RACK_INPUT].respond_to?(:size)
-
-      opts.each { |field, value|
-        env[field] = value  if String === field
-      }
-
-      env
-    end
-  end
-
-  # Rack::MockResponse provides useful helpers for testing your apps.
-  # Usually, you don't create the MockResponse on your own, but use
-  # MockRequest.
-
-  class MockResponse < Rack::Response
-    class << self
-      alias [] new
-    end
-
-    # Headers
-    attr_reader :original_headers, :cookies
-
-    # Errors
-    attr_accessor :errors
-
-    def initialize(status, headers, body, errors = nil)
-      @original_headers = headers
-
-      if errors
-        @errors = errors.string if errors.respond_to?(:string)
-      else
-        @errors = ""
-      end
-
-      super(body, status, headers)
-
-      @cookies = parse_cookies_from_header
-      buffered_body!
-    end
-
-    def =~(other)
-      body =~ other
-    end
-
-    def match(other)
-      body.match other
-    end
-
-    def body
-      # FIXME: apparently users of MockResponse expect the return value of
-      # MockResponse#body to be a string.  However, the real response object
-      # returns the body as a list.
-      #
-      # See spec_showstatus.rb:
-      #
-      #   should "not replace existing messages" do
-      #     ...
-      #     res.body.should == "foo!"
-      #   end
-      buffer = String.new
-
-      super.each do |chunk|
-        buffer << chunk
-      end
-
-      return buffer
-    end
-
-    def empty?
-      [201, 204, 304].include? status
-    end
-
-    def cookie(name)
-      cookies.fetch(name, nil)
-    end
-
-    private
-
-    def parse_cookies_from_header
-      cookies = Hash.new
-      if headers.has_key? 'set-cookie'
-        set_cookie_header = headers.fetch('set-cookie')
-        Array(set_cookie_header).each do |header_value|
-          header_value.split("\n").each do |cookie|
-            cookie_name, cookie_filling = cookie.split('=', 2)
-            cookie_attributes = identify_cookie_attributes cookie_filling
-            parsed_cookie = CGI::Cookie.new(
-              'name' => cookie_name.strip,
-              'value' => cookie_attributes.fetch('value'),
-              'path' => cookie_attributes.fetch('path', nil),
-              'domain' => cookie_attributes.fetch('domain', nil),
-              'expires' => cookie_attributes.fetch('expires', nil),
-              'secure' => cookie_attributes.fetch('secure', false)
-            )
-            cookies.store(cookie_name, parsed_cookie)
-          end
-        end
-      end
-      cookies
-    end
-
-    def identify_cookie_attributes(cookie_filling)
-      cookie_bits = cookie_filling.split(';')
-      cookie_attributes = Hash.new
-      cookie_attributes.store('value', cookie_bits[0].strip)
-      cookie_bits.drop(1).each do |bit|
-        if bit.include? '='
-          cookie_attribute, attribute_value = bit.split('=', 2)
-          cookie_attributes.store(cookie_attribute.strip.downcase, attribute_value.strip)
-        end
-        if bit.include? 'secure'
-          cookie_attributes.store('secure', true)
-        end
-      end
-
-      if cookie_attributes.key? 'max-age'
-        cookie_attributes.store('expires', Time.now + cookie_attributes['max-age'].to_i)
-      elsif cookie_attributes.key? 'expires'
-        cookie_attributes.store('expires', Time.httpdate(cookie_attributes['expires']))
-      end
-
-      cookie_attributes
-    end
-
-  end
-end
+require_relative 'mock_request'