rack-test 0.6.3 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,9 +1,8 @@
1
- require "uri"
2
- require "time"
1
+ require 'uri'
2
+ require 'time'
3
3
 
4
4
  module Rack
5
5
  module Test
6
-
7
6
  class Cookie # :nodoc:
8
7
  include Rack::Utils
9
8
 
@@ -21,8 +20,8 @@ module Rack
21
20
  @name, @value = parse_query(@name_value_raw, ';').to_a.first
22
21
  @options = parse_query(options, ';')
23
22
 
24
- @options["domain"] ||= (uri.host || default_host)
25
- @options["path"] ||= uri.path.sub(/\/[^\/]*\Z/, "")
23
+ @options['domain'] ||= (uri.host || default_host)
24
+ @options['path'] ||= uri.path.sub(/\/[^\/]*\Z/, '')
26
25
  end
27
26
 
28
27
  def replaces?(other)
@@ -41,21 +40,25 @@ module Rack
41
40
 
42
41
  # :api: private
43
42
  def domain
44
- @options["domain"]
43
+ @options['domain']
45
44
  end
46
45
 
47
46
  def secure?
48
- @options.has_key?("secure")
47
+ @options.key?('secure')
48
+ end
49
+
50
+ def http_only?
51
+ @options.key?('HttpOnly')
49
52
  end
50
53
 
51
54
  # :api: private
52
55
  def path
53
- @options["path"].strip || "/"
56
+ ([*@options['path']].first.split(',').first || '/').strip
54
57
  end
55
58
 
56
59
  # :api: private
57
60
  def expires
58
- Time.parse(@options["expires"]) if @options["expires"]
61
+ Time.parse(@options['expires']) if @options['expires']
59
62
  end
60
63
 
61
64
  # :api: private
@@ -67,19 +70,17 @@ module Rack
67
70
  def valid?(uri)
68
71
  uri ||= default_uri
69
72
 
70
- if uri.host.nil?
71
- uri.host = @default_host
72
- end
73
+ uri.host = @default_host if uri.host.nil?
73
74
 
74
75
  real_domain = domain =~ /^\./ ? domain[1..-1] : domain
75
- (!secure? || (secure? && uri.scheme == "https")) &&
76
- uri.host =~ Regexp.new("#{Regexp.escape(real_domain)}$", Regexp::IGNORECASE) &&
77
- uri.path =~ Regexp.new("^#{Regexp.escape(path)}")
76
+ (!secure? || (secure? && uri.scheme == 'https')) &&
77
+ uri.host =~ Regexp.new("#{Regexp.escape(real_domain)}$", Regexp::IGNORECASE) &&
78
+ uri.path =~ Regexp.new("^#{Regexp.escape(path)}")
78
79
  end
79
80
 
80
81
  # :api: private
81
82
  def matches?(uri)
82
- ! expired? && valid?(uri)
83
+ !expired? && valid?(uri)
83
84
  end
84
85
 
85
86
  # :api: private
@@ -88,16 +89,23 @@ module Rack
88
89
  [name, path, domain.reverse] <=> [other.name, other.path, other.domain.reverse]
89
90
  end
90
91
 
91
- protected
92
+ def to_h
93
+ @options.merge(
94
+ 'value' => @value,
95
+ 'HttpOnly' => http_only?,
96
+ 'secure' => secure?
97
+ )
98
+ end
99
+ alias to_hash to_h
100
+
101
+ protected
92
102
 
93
103
  def default_uri
94
- URI.parse("//" + @default_host + "/")
104
+ URI.parse('//' + @default_host + '/')
95
105
  end
96
-
97
106
  end
98
107
 
99
108
  class CookieJar # :nodoc:
100
-
101
109
  # :api: private
102
110
  def initialize(cookies = [], default_host = DEFAULT_HOST)
103
111
  @default_host = default_host
@@ -108,13 +116,17 @@ module Rack
108
116
  def [](name)
109
117
  cookies = hash_for(nil)
110
118
  # TODO: Should be case insensitive
111
- cookies[name] && cookies[name].value
119
+ cookies[name.to_s] && cookies[name.to_s].value
112
120
  end
113
121
 
114
122
  def []=(name, value)
115
123
  merge("#{name}=#{Rack::Utils.escape(value)}")
116
124
  end
117
125
 
126
+ def get_cookie(name)
127
+ hash_for(nil).fetch(name, nil)
128
+ end
129
+
118
130
  def delete(name)
119
131
  @cookies.reject! do |cookie|
120
132
  cookie.name == name
@@ -126,7 +138,7 @@ module Rack
126
138
 
127
139
  if raw_cookies.is_a? String
128
140
  raw_cookies = raw_cookies.split("\n")
129
- raw_cookies.reject!{|c| c.empty? }
141
+ raw_cookies.reject!(&:empty?)
130
142
  end
131
143
 
132
144
  raw_cookies.each do |raw_cookie|
@@ -146,7 +158,7 @@ module Rack
146
158
 
147
159
  # :api: private
148
160
  def for(uri)
149
- hash_for(uri).values.map { |c| c.raw }.join(';')
161
+ hash_for(uri).values.map(&:raw).join(';')
150
162
  end
151
163
 
152
164
  def to_hash
@@ -156,10 +168,10 @@ module Rack
156
168
  cookies[name] = cookie.value
157
169
  end
158
170
 
159
- return cookies
171
+ cookies
160
172
  end
161
173
 
162
- protected
174
+ protected
163
175
 
164
176
  def hash_for(uri = nil)
165
177
  cookies = {}
@@ -173,10 +185,8 @@ module Rack
173
185
  cookies[cookie.name] = cookie if !uri || cookie.matches?(uri)
174
186
  end
175
187
 
176
- return cookies
188
+ cookies
177
189
  end
178
-
179
190
  end
180
-
181
191
  end
182
192
  end
@@ -1,8 +1,7 @@
1
- require "forwardable"
1
+ require 'forwardable'
2
2
 
3
3
  module Rack
4
4
  module Test
5
-
6
5
  # This module serves as the primary integration point for using Rack::Test
7
6
  # in a testing environment. It depends on an app method being defined in the
8
7
  # same context, and provides the Rack::Test API methods (see Rack::Test::Session
@@ -56,26 +55,27 @@ module Rack
56
55
  @_current_session_names ||= [:default]
57
56
  end
58
57
 
59
- METHODS = [
60
- :request,
61
- :get,
62
- :post,
63
- :put,
64
- :patch,
65
- :delete,
66
- :options,
67
- :head,
68
- :follow_redirect!,
69
- :header,
70
- :env,
71
- :set_cookie,
72
- :clear_cookies,
73
- :authorize,
74
- :basic_authorize,
75
- :digest_authorize,
76
- :last_response,
77
- :last_request
78
- ]
58
+ METHODS = %i[
59
+ request
60
+ get
61
+ post
62
+ put
63
+ patch
64
+ delete
65
+ options
66
+ head
67
+ custom_request
68
+ follow_redirect!
69
+ header
70
+ env
71
+ set_cookie
72
+ clear_cookies
73
+ authorize
74
+ basic_authorize
75
+ digest_authorize
76
+ last_response
77
+ last_request
78
+ ].freeze
79
79
 
80
80
  def_delegators :current_session, *METHODS
81
81
  end
@@ -1,14 +1,12 @@
1
1
  module Rack
2
2
  module Test
3
-
4
3
  class MockDigestRequest # :nodoc:
5
-
6
4
  def initialize(params)
7
5
  @params = params
8
6
  end
9
7
 
10
8
  def method_missing(sym)
11
- if @params.has_key? k = sym.to_s
9
+ if @params.key? k = sym.to_s
12
10
  return @params[k]
13
11
  end
14
12
 
@@ -22,8 +20,6 @@ module Rack
22
20
  def response(password)
23
21
  Rack::Auth::Digest::MD5.new(nil).send :digest, self, password
24
22
  end
25
-
26
23
  end
27
-
28
24
  end
29
25
  end
@@ -1,16 +1,14 @@
1
- require "tempfile"
2
- require "fileutils"
1
+ require 'tempfile'
2
+ require 'fileutils'
3
3
 
4
4
  module Rack
5
5
  module Test
6
-
7
6
  # Wraps a Tempfile with a content type. Including one or more UploadedFile's
8
7
  # in the params causes Rack::Test to build and issue a multipart request.
9
8
  #
10
9
  # Example:
11
10
  # post "/photos", "file" => Rack::Test::UploadedFile.new("me.jpg", "image/jpeg")
12
11
  class UploadedFile
13
-
14
12
  # The filename, *not* including the path, of the "uploaded" file
15
13
  attr_reader :original_filename
16
14
 
@@ -20,34 +18,58 @@ module Rack
20
18
  # The content type of the "uploaded" file
21
19
  attr_accessor :content_type
22
20
 
23
- def initialize(path, content_type = "text/plain", binary = false)
24
- raise "#{path} file does not exist" unless ::File.exist?(path)
25
-
21
+ def initialize(content, content_type = 'text/plain', binary = false, original_filename: nil)
22
+ if content.respond_to?(:read)
23
+ initialize_from_io(content, original_filename)
24
+ else
25
+ initialize_from_file_path(content)
26
+ end
26
27
  @content_type = content_type
27
- @original_filename = ::File.basename(path)
28
-
29
- @tempfile = Tempfile.new(@original_filename)
30
- @tempfile.set_encoding(Encoding::BINARY) if @tempfile.respond_to?(:set_encoding)
31
28
  @tempfile.binmode if binary
32
-
33
- FileUtils.copy_file(path, @tempfile.path)
34
29
  end
35
30
 
36
31
  def path
37
- @tempfile.path
32
+ tempfile.path
38
33
  end
39
34
 
40
- alias_method :local_path, :path
35
+ alias local_path path
41
36
 
42
37
  def method_missing(method_name, *args, &block) #:nodoc:
43
- @tempfile.__send__(method_name, *args, &block)
38
+ tempfile.public_send(method_name, *args, &block)
44
39
  end
45
40
 
46
- def respond_to?(method_name, include_private = false) #:nodoc:
47
- @tempfile.respond_to?(method_name, include_private) || super
41
+ def respond_to_missing?(method_name, include_private = false) #:nodoc:
42
+ tempfile.respond_to?(method_name, include_private) || super
48
43
  end
49
44
 
50
- end
45
+ def self.finalize(file)
46
+ proc { actually_finalize file }
47
+ end
48
+
49
+ def self.actually_finalize(file)
50
+ file.close
51
+ file.unlink
52
+ end
51
53
 
54
+ private
55
+
56
+ def initialize_from_io(io, original_filename)
57
+ @tempfile = io
58
+ @original_filename = original_filename || raise(ArgumentError, 'Missing `original_filename` for IO')
59
+ end
60
+
61
+ def initialize_from_file_path(path)
62
+ raise "#{path} file does not exist" unless ::File.exist?(path)
63
+
64
+ @original_filename = ::File.basename(path)
65
+
66
+ @tempfile = Tempfile.new([@original_filename, ::File.extname(path)])
67
+ @tempfile.set_encoding(Encoding::BINARY) if @tempfile.respond_to?(:set_encoding)
68
+
69
+ ObjectSpace.define_finalizer(self, self.class.finalize(@tempfile))
70
+
71
+ FileUtils.copy_file(path, @tempfile.path)
72
+ end
73
+ end
52
74
  end
53
75
  end
@@ -1,38 +1,36 @@
1
1
  module Rack
2
2
  module Test
3
-
4
3
  module Utils # :nodoc:
5
4
  include Rack::Utils
5
+ extend Rack::Utils
6
6
 
7
7
  def build_nested_query(value, prefix = nil)
8
8
  case value
9
9
  when Array
10
- value.map do |v|
11
- unless unescape(prefix) =~ /\[\]$/
12
- prefix = "#{prefix}[]"
13
- end
14
- build_nested_query(v, "#{prefix}")
15
- end.join("&")
10
+ if value.empty?
11
+ "#{prefix}[]="
12
+ else
13
+ value.map do |v|
14
+ prefix = "#{prefix}[]" unless unescape(prefix) =~ /\[\]$/
15
+ build_nested_query(v, prefix.to_s)
16
+ end.join('&')
17
+ end
16
18
  when Hash
17
19
  value.map do |k, v|
18
20
  build_nested_query(v, prefix ? "#{prefix}[#{escape(k)}]" : escape(k))
19
- end.join("&")
21
+ end.join('&')
20
22
  when NilClass
21
23
  prefix.to_s
22
24
  else
23
25
  "#{prefix}=#{escape(value)}"
24
26
  end
25
27
  end
26
-
27
28
  module_function :build_nested_query
28
29
 
29
- def build_multipart(params, first = true)
30
+ def build_multipart(params, first = true, multipart = false)
30
31
  if first
31
- unless params.is_a?(Hash)
32
- raise ArgumentError, "value must be a Hash"
33
- end
32
+ raise ArgumentError, 'value must be a Hash' unless params.is_a?(Hash)
34
33
 
35
- multipart = false
36
34
  query = lambda { |value|
37
35
  case value
38
36
  when Array
@@ -47,7 +45,7 @@ module Rack
47
45
  return nil unless multipart
48
46
  end
49
47
 
50
- flattened_params = Hash.new
48
+ flattened_params = {}
51
49
 
52
50
  params.each do |key, value|
53
51
  k = first ? key.to_s : "[#{key}]"
@@ -55,23 +53,21 @@ module Rack
55
53
  case value
56
54
  when Array
57
55
  value.map do |v|
58
-
59
- if (v.is_a?(Hash))
56
+ if v.is_a?(Hash)
60
57
  nested_params = {}
61
- build_multipart(v, false).each { |subkey, subvalue|
58
+ build_multipart(v, false).each do |subkey, subvalue|
62
59
  nested_params[subkey] = subvalue
63
- }
60
+ end
64
61
  flattened_params["#{k}[]"] ||= []
65
62
  flattened_params["#{k}[]"] << nested_params
66
63
  else
67
64
  flattened_params["#{k}[]"] = value
68
65
  end
69
-
70
66
  end
71
67
  when Hash
72
- build_multipart(value, false).each { |subkey, subvalue|
68
+ build_multipart(value, false).each do |subkey, subvalue|
73
69
  flattened_params[k + subkey] = subvalue
74
- }
70
+ end
75
71
  else
76
72
  flattened_params[k] = value
77
73
  end
@@ -83,27 +79,28 @@ module Rack
83
79
  flattened_params
84
80
  end
85
81
  end
86
-
87
82
  module_function :build_multipart
88
83
 
89
- private
84
+ private
85
+
90
86
  def build_parts(parameters)
91
87
  get_parts(parameters).join + "--#{MULTIPART_BOUNDARY}--\r"
92
88
  end
89
+ module_function :build_parts
93
90
 
94
91
  def get_parts(parameters)
95
- parameters.map { |name, value|
96
- if name =~ /\[\]\Z/ && value.is_a?(Array) && value.all? {|v| v.is_a?(Hash)}
97
- value.map { |hash|
92
+ parameters.map do |name, value|
93
+ if name =~ /\[\]\Z/ && value.is_a?(Array) && value.all? { |v| v.is_a?(Hash) }
94
+ value.map do |hash|
98
95
  new_value = {}
99
- hash.each { |k, v| new_value[name+k] = v }
96
+ hash.each { |k, v| new_value[name + k] = v }
100
97
  get_parts(new_value).join
101
- }.join
98
+ end.join
102
99
  else
103
100
  if value.respond_to?(:original_filename)
104
101
  build_file_part(name, value)
105
102
 
106
- elsif value.is_a?(Array) and value.all? { |v| v.respond_to?(:original_filename) }
103
+ elsif value.is_a?(Array) && value.all? { |v| v.respond_to?(:original_filename) }
107
104
  value.map do |v|
108
105
  build_file_part(name, v)
109
106
  end.join
@@ -113,15 +110,14 @@ module Rack
113
110
  Rack::Test.encoding_aware_strings? ? primitive_part.force_encoding('BINARY') : primitive_part
114
111
  end
115
112
  end
116
- }
113
+ end
117
114
  end
115
+ module_function :get_parts
118
116
 
119
117
  def build_primitive_part(parameter_name, value)
120
- unless value.is_a? Array
121
- value = [value]
122
- end
118
+ value = [value] unless value.is_a? Array
123
119
  value.map do |v|
124
- <<-EOF
120
+ <<-EOF
125
121
  --#{MULTIPART_BOUNDARY}\r
126
122
  Content-Disposition: form-data; name="#{parameter_name}"\r
127
123
  \r
@@ -129,22 +125,20 @@ Content-Disposition: form-data; name="#{parameter_name}"\r
129
125
  EOF
130
126
  end.join
131
127
  end
128
+ module_function :build_primitive_part
132
129
 
133
130
  def build_file_part(parameter_name, uploaded_file)
134
- ::File.open(uploaded_file.path, "rb") do |physical_file|
135
- physical_file.set_encoding(Encoding::BINARY) if physical_file.respond_to?(:set_encoding)
136
- <<-EOF
131
+ uploaded_file.set_encoding(Encoding::BINARY) if uploaded_file.respond_to?(:set_encoding)
132
+ <<-EOF
137
133
  --#{MULTIPART_BOUNDARY}\r
138
134
  Content-Disposition: form-data; name="#{parameter_name}"; filename="#{escape(uploaded_file.original_filename)}"\r
139
135
  Content-Type: #{uploaded_file.content_type}\r
140
- Content-Length: #{::File.stat(uploaded_file.path).size}\r
136
+ Content-Length: #{uploaded_file.size}\r
141
137
  \r
142
- #{physical_file.read}\r
138
+ #{uploaded_file.read}\r
143
139
  EOF
144
- end
145
140
  end
146
-
141
+ module_function :build_file_part
147
142
  end
148
-
149
143
  end
150
144
  end