rack-test 0.4.1 → 0.4.2

Sign up to get free protection for your applications and to get access to all the features.
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