`Rack::Lint.new(nil)` is invalid.
[rack.git] / lib / rack / mock_response.rb
blob9af8079e1eb595825447c670e36ce6198a98fed3
1 # frozen_string_literal: true
3 require 'cgi/cookie'
4 require 'time'
6 require_relative 'response'
8 module Rack
9   # Rack::MockResponse provides useful helpers for testing your apps.
10   # Usually, you don't create the MockResponse on your own, but use
11   # MockRequest.
13   class MockResponse < Rack::Response
14     class << self
15       alias [] new
16     end
18     # Headers
19     attr_reader :original_headers, :cookies
21     # Errors
22     attr_accessor :errors
24     def initialize(status, headers, body, errors = nil)
25       @original_headers = headers
27       if errors
28         @errors = errors.string if errors.respond_to?(:string)
29       else
30         @errors = ""
31       end
33       super(body, status, headers)
35       @cookies = parse_cookies_from_header
36       buffered_body!
37     end
39     def =~(other)
40       body =~ other
41     end
43     def match(other)
44       body.match other
45     end
47     def body
48       return @buffered_body if defined?(@buffered_body)
50       # FIXME: apparently users of MockResponse expect the return value of
51       # MockResponse#body to be a string.  However, the real response object
52       # returns the body as a list.
53       #
54       # See spec_showstatus.rb:
55       #
56       #   should "not replace existing messages" do
57       #     ...
58       #     res.body.should == "foo!"
59       #   end
60       buffer = @buffered_body = String.new
62       @body.each do |chunk|
63         buffer << chunk
64       end
66       return buffer
67     end
69     def empty?
70       [201, 204, 304].include? status
71     end
73     def cookie(name)
74       cookies.fetch(name, nil)
75     end
77     private
79     def parse_cookies_from_header
80       cookies = Hash.new
81       set_cookie_header = headers['set-cookie']
82       if set_cookie_header && !set_cookie_header.empty?
83         Array(set_cookie_header).each do |cookie|
84           cookie_name, cookie_filling = cookie.split('=', 2)
85           cookie_attributes = identify_cookie_attributes cookie_filling
86           parsed_cookie = CGI::Cookie.new(
87             'name' => cookie_name.strip,
88             'value' => cookie_attributes.fetch('value'),
89             'path' => cookie_attributes.fetch('path', nil),
90             'domain' => cookie_attributes.fetch('domain', nil),
91             'expires' => cookie_attributes.fetch('expires', nil),
92             'secure' => cookie_attributes.fetch('secure', false)
93           )
94           cookies.store(cookie_name, parsed_cookie)
95         end
96       end
97       cookies
98     end
100     def identify_cookie_attributes(cookie_filling)
101       cookie_bits = cookie_filling.split(';')
102       cookie_attributes = Hash.new
103       cookie_attributes.store('value', cookie_bits[0].strip)
104       cookie_bits.drop(1).each do |bit|
105         if bit.include? '='
106           cookie_attribute, attribute_value = bit.split('=', 2)
107           cookie_attributes.store(cookie_attribute.strip.downcase, attribute_value.strip)
108         end
109         if bit.include? 'secure'
110           cookie_attributes.store('secure', true)
111         end
112       end
114       if cookie_attributes.key? 'max-age'
115         cookie_attributes.store('expires', Time.now + cookie_attributes['max-age'].to_i)
116       elsif cookie_attributes.key? 'expires'
117         cookie_attributes.store('expires', Time.httpdate(cookie_attributes['expires']))
118       end
120       cookie_attributes
121     end
123   end