summary refs log tree commit
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/rack.rb4
-rw-r--r--lib/rack/mock.rb285
-rw-r--r--lib/rack/mock_request.rb166
-rw-r--r--lib/rack/mock_response.rb124
4 files changed, 293 insertions, 286 deletions
diff --git a/lib/rack.rb b/lib/rack.rb
index 93646fc0..5b87ea1b 100644
--- a/lib/rack.rb
+++ b/lib/rack.rb
@@ -55,8 +55,8 @@ module Rack
   autoload :Utils, "rack/utils"
   autoload :Multipart, "rack/multipart"
 
-  autoload :MockRequest, "rack/mock"
-  autoload :MockResponse, "rack/mock"
+  autoload :MockRequest, "rack/mock_request"
+  autoload :MockResponse, "rack/mock_response"
 
   autoload :Request, "rack/request"
   autoload :Response, "rack/response"
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'
diff --git a/lib/rack/mock_request.rb b/lib/rack/mock_request.rb
new file mode 100644
index 00000000..b6d7ef4f
--- /dev/null
+++ b/lib/rack/mock_request.rb
@@ -0,0 +1,166 @@
+# frozen_string_literal: true
+
+require 'uri'
+require 'stringio'
+
+require_relative 'constants'
+require_relative 'mock_response'
+
+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
+end
diff --git a/lib/rack/mock_response.rb b/lib/rack/mock_response.rb
new file mode 100644
index 00000000..3142f68a
--- /dev/null
+++ b/lib/rack/mock_response.rb
@@ -0,0 +1,124 @@
+# frozen_string_literal: true
+
+require 'cgi/cookie'
+require 'time'
+
+require_relative 'response'
+
+module Rack
+  # 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