rack-test 0.4.1 → 0.4.2

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.
data/History.txt CHANGED
@@ -1,3 +1,18 @@
1
+ == 0.4.2 / 2009-09-01
2
+
3
+ * Minor enhancements
4
+
5
+ * Merge in rack/master's build_multipart method which covers additional cases
6
+ * Accept raw :params string input and merge it with the query string
7
+ * Stringify and upcase request method (e.g. :post => "POST") (Josh Peek)
8
+
9
+ * Bug fixes
10
+
11
+ * Properly convert hashes with nil values (e.g. :foo => nil becomes simply "foo", not "foo=")
12
+ * Prepend a slash to the URI path if it doesn't start with one (Josh Peek)
13
+ * Requiring Rack-Test never modifies the Ruby load path anymore (Josh Peek)
14
+ * Fixed using multiple cookies in a string on Ruby 1.8 (Tuomas Kareinen and Hermanni Hyytiälä)
15
+
1
16
  == 0.4.1 / 2009-08-06
2
17
 
3
18
  * Minor enhancements
data/Rakefile CHANGED
@@ -23,6 +23,8 @@ end
23
23
 
24
24
  Spec::Rake::SpecTask.new do |t|
25
25
  t.spec_opts = ['--options', "\"#{File.dirname(__FILE__)}/spec/spec.opts\""]
26
+ t.libs << 'lib'
27
+ t.libs << 'spec'
26
28
  end
27
29
 
28
30
  desc "Run all specs in spec directory with RCov"
@@ -45,7 +47,7 @@ task :whitespace do
45
47
  sh %{find . -name '*.rb' -exec sed -i '' 's/ *$//g' {} \\;}
46
48
  end
47
49
 
48
- task :spec => :check_dependencies
50
+ task :spec => :check_dependencies if defined?(Jeweler)
49
51
 
50
52
  desc "Run the specs"
51
53
  task :default => :spec
data/lib/rack/test.rb CHANGED
@@ -1,7 +1,3 @@
1
- unless $LOAD_PATH.include?(File.expand_path(File.dirname(__FILE__) + "/.."))
2
- $LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__) + "/.."))
3
- end
4
-
5
1
  require "uri"
6
2
  require "rack"
7
3
  require "rack/mock_session"
@@ -13,7 +9,7 @@ require "rack/test/uploaded_file"
13
9
 
14
10
  module Rack
15
11
  module Test
16
- VERSION = ::File.read(::File.join(::File.dirname(__FILE__), "..", "..", "VERSION")).strip
12
+ VERSION = "0.4.2"
17
13
 
18
14
  DEFAULT_HOST = "example.org"
19
15
  MULTIPART_BOUNDARY = "----------XnJLe9ZIbbGUYtzPQJ16u1"
@@ -145,6 +141,7 @@ module Rack
145
141
 
146
142
  def env_for(path, env)
147
143
  uri = URI.parse(path)
144
+ uri.path = "/#{uri.path}" unless uri.path[0] == ?/
148
145
  uri.host ||= @default_host
149
146
 
150
147
  env = default_env.merge(env)
@@ -152,26 +149,32 @@ module Rack
152
149
  env.update("HTTPS" => "on") if URI::HTTPS === uri
153
150
  env["X-Requested-With"] = "XMLHttpRequest" if env[:xhr]
154
151
 
155
- if (env[:method] == "POST" || env["REQUEST_METHOD"] == "POST" ||
156
- env[:method] == "PUT" || env["REQUEST_METHOD"] == "PUT") && !env.has_key?(:input)
157
- env["CONTENT_TYPE"] ||= "application/x-www-form-urlencoded"
152
+ # TODO: Remove this after Rack 1.1 has been released.
153
+ # Stringifying and upcasing methods has be commit upstream
154
+ env["REQUEST_METHOD"] ||= env[:method] ? env[:method].to_s.upcase : "GET"
158
155
 
159
- multipart = (Hash === env[:params]) &&
160
- env[:params].any? { |_, v| UploadedFile === v }
156
+ if env["REQUEST_METHOD"] == "GET"
157
+ params = env[:params] || {}
158
+ params = parse_nested_query(params) if params.is_a?(String)
159
+ params.update(parse_query(uri.query))
160
+ uri.query = build_nested_query(params)
161
+ elsif !env.has_key?(:input)
162
+ env["CONTENT_TYPE"] ||= "application/x-www-form-urlencoded"
161
163
 
162
- if multipart
163
- env[:input] = multipart_body(env.delete(:params))
164
- env["CONTENT_LENGTH"] ||= env[:input].length.to_s
165
- env["CONTENT_TYPE"] = "multipart/form-data; boundary=#{MULTIPART_BOUNDARY}"
164
+ if env[:params].is_a?(Hash)
165
+ if data = build_multipart(env[:params])
166
+ env[:input] = data
167
+ env["CONTENT_LENGTH"] ||= data.length.to_s
168
+ env["CONTENT_TYPE"] = "multipart/form-data; boundary=#{MULTIPART_BOUNDARY}"
169
+ else
170
+ env[:input] = params_to_string(env[:params])
171
+ end
166
172
  else
167
- env[:input] = params_to_string(env.delete(:params))
173
+ env[:input] = env[:params]
168
174
  end
169
175
  end
170
176
 
171
- params = env[:params] || {}
172
- params.update(parse_query(uri.query))
173
-
174
- uri.query = requestify(params)
177
+ env.delete(:params)
175
178
 
176
179
  if env.has_key?(:cookie)
177
180
  set_cookie(env.delete(:cookie), uri)
@@ -233,7 +236,7 @@ module Rack
233
236
 
234
237
  def params_to_string(params)
235
238
  case params
236
- when Hash then requestify(params)
239
+ when Hash then build_nested_query(params)
237
240
  when nil then ""
238
241
  else params
239
242
  end
@@ -116,7 +116,8 @@ module Rack
116
116
  def merge(raw_cookies, uri = nil)
117
117
  return unless raw_cookies
118
118
 
119
- Array(raw_cookies).join("\n").split("\n").each do |raw_cookie|
119
+ raw_cookies = raw_cookies.split("\n") if raw_cookies.is_a? String
120
+ raw_cookies.each do |raw_cookie|
120
121
  cookie = Cookie.new(raw_cookie, uri, @default_host)
121
122
  self << cookie if cookie.valid?(uri)
122
123
  end
@@ -4,70 +4,96 @@ module Rack
4
4
  module Utils
5
5
  include Rack::Utils
6
6
 
7
- def requestify(value, prefix = nil)
7
+ def build_nested_query(value, prefix = nil)
8
8
  case value
9
9
  when Array
10
10
  value.map do |v|
11
- requestify(v, "#{prefix}[]")
11
+ build_nested_query(v, "#{prefix}[]")
12
12
  end.join("&")
13
13
  when Hash
14
14
  value.map do |k, v|
15
- requestify(v, prefix ? "#{prefix}[#{escape(k)}]" : escape(k))
15
+ build_nested_query(v, prefix ? "#{prefix}[#{escape(k)}]" : escape(k))
16
16
  end.join("&")
17
+ when NilClass
18
+ prefix.to_s
17
19
  else
18
20
  "#{prefix}=#{escape(value)}"
19
21
  end
20
22
  end
21
23
 
22
- module_function :requestify
24
+ module_function :build_nested_query
23
25
 
24
- def multipart_requestify(params, first=true)
25
- p = Hash.new
26
+ def build_multipart(params, first = true)
27
+ if first
28
+ unless params.is_a?(Hash)
29
+ raise ArgumentError, "value must be a Hash"
30
+ end
31
+
32
+ multipart = false
33
+ query = lambda { |value|
34
+ case value
35
+ when Array
36
+ value.each(&query)
37
+ when Hash
38
+ value.values.each(&query)
39
+ when UploadedFile
40
+ multipart = true
41
+ end
42
+ }
43
+ params.values.each(&query)
44
+ return nil unless multipart
45
+ end
46
+
47
+ flattened_params = Hash.new
26
48
 
27
49
  params.each do |key, value|
28
50
  k = first ? key.to_s : "[#{key}]"
29
51
 
30
- if Hash === value
31
- multipart_requestify(value, false).each do |subkey, subvalue|
32
- p[k + subkey] = subvalue
33
- end
52
+ case value
53
+ when Array
54
+ value.map { |v|
55
+ build_multipart(v, false).each { |subkey, subvalue|
56
+ flattened_params["#{k}[]#{subkey}"] = subvalue
57
+ }
58
+ }
59
+ when Hash
60
+ build_multipart(value, false).each { |subkey, subvalue|
61
+ flattened_params[k + subkey] = subvalue
62
+ }
34
63
  else
35
- p[k] = value
64
+ flattened_params[k] = value
36
65
  end
37
66
  end
38
67
 
39
- return p
40
- end
41
-
42
- module_function :multipart_requestify
43
-
44
- def multipart_body(params)
45
- multipart_requestify(params).map do |key, value|
46
- if value.respond_to?(:original_filename)
47
- ::File.open(value.path, "rb") do |f|
48
- f.set_encoding(Encoding::BINARY) if f.respond_to?(:set_encoding)
49
-
50
- <<-EOF
68
+ if first
69
+ flattened_params.map { |name, file|
70
+ if file.respond_to?(:original_filename)
71
+ ::File.open(file.path, "rb") do |f|
72
+ f.set_encoding(Encoding::BINARY) if f.respond_to?(:set_encoding)
73
+ <<-EOF
51
74
  --#{MULTIPART_BOUNDARY}\r
52
- Content-Disposition: form-data; name="#{key}"; filename="#{escape(value.original_filename)}"\r
53
- Content-Type: #{value.content_type}\r
54
- Content-Length: #{::File.stat(value.path).size}\r
75
+ Content-Disposition: form-data; name="#{name}"; filename="#{escape(file.original_filename)}"\r
76
+ Content-Type: #{file.content_type}\r
77
+ Content-Length: #{::File.stat(file.path).size}\r
55
78
  \r
56
79
  #{f.read}\r
57
80
  EOF
58
- end
59
- else
81
+ end
82
+ else
60
83
  <<-EOF
61
84
  --#{MULTIPART_BOUNDARY}\r
62
- Content-Disposition: form-data; name="#{key}"\r
85
+ Content-Disposition: form-data; name="#{name}"\r
63
86
  \r
64
- #{value}\r
87
+ #{file}\r
65
88
  EOF
66
- end
67
- end.join("")+"--#{MULTIPART_BOUNDARY}--\r"
89
+ end
90
+ }.join + "--#{MULTIPART_BOUNDARY}--\r"
91
+ else
92
+ flattened_params
93
+ end
68
94
  end
69
95
 
70
- module_function :multipart_body
96
+ module_function :build_multipart
71
97
 
72
98
  end
73
99
 
data/rack-test.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{rack-test}
8
- s.version = "0.4.1"
8
+ s.version = "0.4.2"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Bryan Helmkamp"]
12
- s.date = %q{2009-08-06}
12
+ s.date = %q{2009-09-01}
13
13
  s.email = %q{bryan@brynary.com}
14
14
  s.extra_rdoc_files = [
15
15
  "MIT-LICENSE.txt",
@@ -22,7 +22,6 @@ Gem::Specification.new do |s|
22
22
  "MIT-LICENSE.txt",
23
23
  "README.rdoc",
24
24
  "Rakefile",
25
- "VERSION",
26
25
  "lib/rack/mock_session.rb",
27
26
  "lib/rack/test.rb",
28
27
  "lib/rack/test/cookie_jar.rb",
@@ -47,7 +46,7 @@ Gem::Specification.new do |s|
47
46
  s.rdoc_options = ["--charset=UTF-8"]
48
47
  s.require_paths = ["lib"]
49
48
  s.rubyforge_project = %q{rack-test}
50
- s.rubygems_version = %q{1.3.4}
49
+ s.rubygems_version = %q{1.3.5}
51
50
  s.summary = %q{Simple testing API built on Rack}
52
51
  s.test_files = [
53
52
  "spec/fixtures/fake_app.rb",
@@ -92,6 +92,12 @@ module Rack
92
92
  "Set"
93
93
  end
94
94
 
95
+ get "/cookies/set-multiple" do
96
+ response.set_cookie("key1", :value => "value1")
97
+ response.set_cookie("key2", :value => "value2")
98
+ "Set"
99
+ end
100
+
95
101
  post "/" do
96
102
  "Hello, POST: #{params.inspect}"
97
103
  end
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + "/../../spec_helper"
1
+ require "spec_helper"
2
2
 
3
3
  describe Rack::Test::Session do
4
4
  def have_body(string)
@@ -144,6 +144,12 @@ describe Rack::Test::Session do
144
144
  last_request.cookies.should == { "value" => "10", "foo" => "bar" }
145
145
  end
146
146
 
147
+ it "parses multiple cookies properly" do
148
+ get "/cookies/set-multiple"
149
+ get "/cookies/show"
150
+ last_request.cookies.should == { "key1" => "value1", "key2" => "value2" }
151
+ end
152
+
147
153
  it "supports multiple sessions" do
148
154
  with_session(:first) do
149
155
  get "/cookies/set", "value" => "1"
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + "/../../spec_helper"
1
+ require "spec_helper"
2
2
 
3
3
  describe Rack::Test::Session do
4
4
  context "HTTP Digest authentication" do
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + "/../../spec_helper"
1
+ require "spec_helper"
2
2
 
3
3
  describe Rack::Test::Session do
4
4
 
@@ -1,44 +1,97 @@
1
- require File.dirname(__FILE__) + "/../../spec_helper"
1
+ require "spec_helper"
2
2
 
3
3
  describe Rack::Test::Utils do
4
4
  include Rack::Test::Utils
5
5
 
6
- describe "requestify" do
6
+ describe "build_nested_query" do
7
7
  it "converts empty strings to =" do
8
- requestify("").should == "="
8
+ build_nested_query("").should == "="
9
9
  end
10
10
 
11
- it "converts nil to =" do
12
- requestify(nil).should == "="
11
+ it "converts nil to an empty string" do
12
+ build_nested_query(nil).should == ""
13
+ end
14
+
15
+ it "converts hashes with nil values" do
16
+ build_nested_query(:a => nil).should == "a"
13
17
  end
14
18
 
15
19
  it "converts hashes" do
16
- requestify(:a => 1).should == "a=1"
20
+ build_nested_query(:a => 1).should == "a=1"
17
21
  end
18
22
 
19
23
  it "converts hashes with multiple keys" do
20
24
  hash = { :a => 1, :b => 2 }
21
- ["a=1&b=2", "b=2&a=1"].should include(requestify(hash))
25
+ ["a=1&b=2", "b=2&a=1"].should include(build_nested_query(hash))
22
26
  end
23
27
 
24
28
  it "converts arrays with one element" do
25
- requestify(:a => [1]).should == "a[]=1"
29
+ build_nested_query(:a => [1]).should == "a[]=1"
26
30
  end
27
31
 
28
32
  it "converts arrays with multiple elements" do
29
- requestify(:a => [1, 2]).should == "a[]=1&a[]=2"
33
+ build_nested_query(:a => [1, 2]).should == "a[]=1&a[]=2"
30
34
  end
31
35
 
32
36
  it "converts nested hashes" do
33
- requestify(:a => { :b => 1 }).should == "a[b]=1"
37
+ build_nested_query(:a => { :b => 1 }).should == "a[b]=1"
34
38
  end
35
39
 
36
40
  it "converts arrays nested in a hash" do
37
- requestify(:a => { :b => [1, 2] }).should == "a[b][]=1&a[b][]=2"
41
+ build_nested_query(:a => { :b => [1, 2] }).should == "a[b][]=1&a[b][]=2"
38
42
  end
39
43
 
40
44
  it "converts arrays of hashes" do
41
- requestify(:a => [{ :b => 2}, { :c => 3}]).should == "a[][b]=2&a[][c]=3"
45
+ build_nested_query(:a => [{ :b => 2}, { :c => 3}]).should == "a[][b]=2&a[][c]=3"
46
+ end
47
+ end
48
+
49
+ describe "build_multipart" do
50
+ it "builds multipart bodies" do
51
+ files = Rack::Test::UploadedFile.new(multipart_file("foo.txt"))
52
+ data = build_multipart("submit-name" => "Larry", "files" => files)
53
+
54
+ options = {
55
+ "CONTENT_TYPE" => "multipart/form-data; boundary=#{Rack::Test::MULTIPART_BOUNDARY}",
56
+ "CONTENT_LENGTH" => data.length.to_s,
57
+ :input => StringIO.new(data)
58
+ }
59
+ env = Rack::MockRequest.env_for("/", options)
60
+ params = Rack::Utils::Multipart.parse_multipart(env)
61
+ params["submit-name"].should == "Larry"
62
+ params["files"][:filename].should == "foo.txt"
63
+ params["files"][:tempfile].read.should == "bar\n"
64
+ end
65
+
66
+ it "builds nested multipart bodies" do
67
+ files = Rack::Test::UploadedFile.new(multipart_file("foo.txt"))
68
+ data = build_multipart("people" => [{"submit-name" => "Larry", "files" => files}])
69
+
70
+ options = {
71
+ "CONTENT_TYPE" => "multipart/form-data; boundary=#{Rack::Test::MULTIPART_BOUNDARY}",
72
+ "CONTENT_LENGTH" => data.length.to_s,
73
+ :input => StringIO.new(data)
74
+ }
75
+ env = Rack::MockRequest.env_for("/", options)
76
+ params = Rack::Utils::Multipart.parse_multipart(env)
77
+ params["people"][0]["submit-name"].should == "Larry"
78
+ params["people"][0]["files"][:filename].should == "foo.txt"
79
+ params["people"][0]["files"][:tempfile].read.should == "bar\n"
80
+ end
81
+
82
+ it "should return nil if no UploadedFiles were used" do
83
+ data = build_multipart("people" => [{"submit-name" => "Larry", "files" => "contents"}])
84
+ data.should be_nil
85
+ end
86
+
87
+ it "raises ArgumentErrors if params is not a Hash" do
88
+ lambda {
89
+ build_multipart("foo=bar")
90
+ }.should raise_error(ArgumentError, "value must be a Hash")
91
+ end
92
+
93
+ def multipart_file(name)
94
+ File.join(File.dirname(__FILE__), "..", "..", "fixtures", name.to_s)
42
95
  end
43
96
  end
44
97
  end
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + "/../spec_helper"
1
+ require "spec_helper"
2
2
 
3
3
  describe Rack::Test::Session do
4
4
  describe "initialization" do
@@ -71,6 +71,41 @@ describe Rack::Test::Session do
71
71
  last_response.body.should be_empty
72
72
  end
73
73
 
74
+ it "allows passing :input in for POSTs" do
75
+ request "/", :method => :post, :input => "foo"
76
+ last_request.env["rack.input"].read.should == "foo"
77
+ end
78
+
79
+ it "converts method names to a uppercase strings" do
80
+ request "/", :method => :put
81
+ last_request.env["REQUEST_METHOD"].should == "PUT"
82
+ end
83
+
84
+ it "prepends a slash to the URI path" do
85
+ request "foo"
86
+ last_request.env["PATH_INFO"].should == "/foo"
87
+ end
88
+
89
+ it "accepts params and builds query strings for GET requests" do
90
+ request "/foo?baz=2", :params => {:foo => {:bar => "1"}}
91
+ last_request.env["QUERY_STRING"].should == "baz=2&foo[bar]=1"
92
+ end
93
+
94
+ it "accepts raw input in params for GET requests" do
95
+ request "/foo?baz=2", :params => "foo[bar]=1"
96
+ last_request.env["QUERY_STRING"].should == "baz=2&foo[bar]=1"
97
+ end
98
+
99
+ it "accepts params and builds url encoded params for POST requests" do
100
+ request "/foo", :method => :post, :params => {:foo => {:bar => "1"}}
101
+ last_request.env["rack.input"].read.should == "foo[bar]=1"
102
+ end
103
+
104
+ it "accepts raw input in params for POST requests" do
105
+ request "/foo", :method => :post, :params => "foo[bar]=1"
106
+ last_request.env["rack.input"].read.should == "foo[bar]=1"
107
+ end
108
+
74
109
  context "when input is given" do
75
110
  it "should send the input" do
76
111
  request "/", :method => "POST", :input => "foo"
@@ -105,6 +140,11 @@ describe Rack::Test::Session do
105
140
  end
106
141
 
107
142
  context "when the URL is https://" do
143
+ it "sets rack.url_scheme to https" do
144
+ get "https://example.org/"
145
+ last_request.env["rack.url_scheme"].should == "https"
146
+ end
147
+
108
148
  it "sets SERVER_PORT to 443" do
109
149
  get "https://example.org/"
110
150
  last_request.env["SERVER_PORT"].should == "443"
data/spec/spec_helper.rb CHANGED
@@ -3,7 +3,7 @@ require "spec"
3
3
 
4
4
  gem "rack", "~> 1.0.0"
5
5
 
6
- require File.expand_path(File.dirname(__FILE__) + "/../lib/rack/test")
6
+ require "rack/test"
7
7
  require File.dirname(__FILE__) + "/fixtures/fake_app"
8
8
 
9
9
  Spec::Runner.configure do |config|
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rack-test
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.1
4
+ version: 0.4.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bryan Helmkamp
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-08-06 00:00:00 -04:00
12
+ date: 2009-09-01 00:00:00 -04:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -29,7 +29,6 @@ files:
29
29
  - MIT-LICENSE.txt
30
30
  - README.rdoc
31
31
  - Rakefile
32
- - VERSION
33
32
  - lib/rack/mock_session.rb
34
33
  - lib/rack/test.rb
35
34
  - lib/rack/test/cookie_jar.rb
@@ -73,7 +72,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
73
72
  requirements: []
74
73
 
75
74
  rubyforge_project: rack-test
76
- rubygems_version: 1.3.4
75
+ rubygems_version: 1.3.5
77
76
  signing_key:
78
77
  specification_version: 3
79
78
  summary: Simple testing API built on Rack
data/VERSION DELETED
@@ -1 +0,0 @@
1
- 0.4.1