rack-test 0.6.2 → 0.6.3

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -1,6 +1,8 @@
1
- source :rubygems
1
+ source 'https://rubygems.org'
2
2
 
3
3
  gem 'rspec'
4
4
  gem "rack"
5
5
  gem "sinatra"
6
6
  gem 'rake'
7
+
8
+ gem "codeclimate-test-reporter", group: :test, require: nil
@@ -1,30 +1,40 @@
1
1
  GEM
2
- remote: http://rubygems.org/
2
+ remote: https://rubygems.org/
3
3
  specs:
4
- diff-lcs (1.1.3)
5
- rack (1.4.0)
6
- rack-protection (1.2.0)
4
+ codeclimate-test-reporter (0.3.0)
5
+ simplecov (>= 0.7.1, < 1.0.0)
6
+ diff-lcs (1.2.3)
7
+ docile (1.1.3)
8
+ multi_json (1.9.0)
9
+ rack (1.5.2)
10
+ rack-protection (1.5.0)
7
11
  rack
8
- rake (0.9.2)
9
- rspec (2.8.0)
10
- rspec-core (~> 2.8.0)
11
- rspec-expectations (~> 2.8.0)
12
- rspec-mocks (~> 2.8.0)
13
- rspec-core (2.8.0)
14
- rspec-expectations (2.8.0)
15
- diff-lcs (~> 1.1.2)
16
- rspec-mocks (2.8.0)
17
- sinatra (1.3.2)
18
- rack (~> 1.3, >= 1.3.6)
19
- rack-protection (~> 1.2)
20
- tilt (~> 1.3, >= 1.3.3)
21
- tilt (1.3.3)
12
+ rake (10.0.4)
13
+ rspec (2.13.0)
14
+ rspec-core (~> 2.13.0)
15
+ rspec-expectations (~> 2.13.0)
16
+ rspec-mocks (~> 2.13.0)
17
+ rspec-core (2.13.1)
18
+ rspec-expectations (2.13.0)
19
+ diff-lcs (>= 1.1.3, < 2.0)
20
+ rspec-mocks (2.13.1)
21
+ simplecov (0.8.2)
22
+ docile (~> 1.1.0)
23
+ multi_json
24
+ simplecov-html (~> 0.8.0)
25
+ simplecov-html (0.8.0)
26
+ sinatra (1.4.2)
27
+ rack (~> 1.5, >= 1.5.2)
28
+ rack-protection (~> 1.4)
29
+ tilt (~> 1.3, >= 1.3.4)
30
+ tilt (1.3.7)
22
31
 
23
32
  PLATFORMS
24
33
  java
25
34
  ruby
26
35
 
27
36
  DEPENDENCIES
37
+ codeclimate-test-reporter
28
38
  rack
29
39
  rake
30
40
  rspec
@@ -1,3 +1,16 @@
1
+ == 0.6.3 / 2015-01-09
2
+
3
+ * Minor enhancements
4
+
5
+ * Expose an env helper for persistently configuring the env as needed
6
+ (Darío Javier Cravero #80)
7
+ * Expose the tempfile of UploadedFile (Sytse Sijbrandij #67)
8
+
9
+ * Bug fixes
10
+
11
+ * Improve support for arrays of hashes in multipart forms (Murray Steele #69)
12
+ * Improve test for query strings (Paul Grayson #66)
13
+
1
14
  == 0.6.2 / 2012-09-27
2
15
 
3
16
  * Minor enhancements
@@ -1,4 +1,4 @@
1
- = Rack::Test {<img src="https://codeclimate.com/badge.png" />}[https://codeclimate.com/github/brynary/rack-test]
1
+ = Rack::Test {<img src="https://codeclimate.com/github/brynary/rack-test.png" />}[https://codeclimate.com/github/brynary/rack-test] {<img src="https://codeclimate.com/github/brynary/rack-test/coverage.png" />}[https://codeclimate.com/github/brynary/rack-test]
2
2
 
3
3
  - Code: http://github.com/brynary/rack-test
4
4
 
@@ -9,7 +9,7 @@ require "rack/test/uploaded_file"
9
9
 
10
10
  module Rack
11
11
  module Test
12
- VERSION = "0.6.2"
12
+ VERSION = "0.6.3"
13
13
 
14
14
  DEFAULT_HOST = "example.org"
15
15
  MULTIPART_BOUNDARY = "----------XnJLe9ZIbbGUYtzPQJ16u1"
@@ -35,6 +35,7 @@ module Rack
35
35
  # (See README.rdoc for an example)
36
36
  def initialize(mock_session)
37
37
  @headers = {}
38
+ @env = {}
38
39
 
39
40
  if mock_session.is_a?(MockSession)
40
41
  @rack_mock_session = mock_session
@@ -139,6 +140,19 @@ module Rack
139
140
  end
140
141
  end
141
142
 
143
+ # Set an env var to be included on all subsequent requests through the
144
+ # session. Use a value of nil to remove a previously configured env.
145
+ #
146
+ # Example:
147
+ # env "rack.session", {:csrf => 'token'}
148
+ def env(name, value)
149
+ if value.nil?
150
+ @env.delete(name)
151
+ else
152
+ @env[name] = value
153
+ end
154
+ end
155
+
142
156
  # Set the username and password for HTTP Basic authorization, to be
143
157
  # included in subsequent requests in the HTTP_AUTHORIZATION header.
144
158
  #
@@ -271,7 +285,7 @@ module Rack
271
285
  end
272
286
 
273
287
  def default_env
274
- { "rack.test" => true, "REMOTE_ADDR" => "127.0.0.1" }.merge(headers_for_env)
288
+ { "rack.test" => true, "REMOTE_ADDR" => "127.0.0.1" }.merge(@env).merge(headers_for_env)
275
289
  end
276
290
 
277
291
  def headers_for_env
@@ -67,6 +67,7 @@ module Rack
67
67
  :head,
68
68
  :follow_redirect!,
69
69
  :header,
70
+ :env,
70
71
  :set_cookie,
71
72
  :clear_cookies,
72
73
  :authorize,
@@ -14,6 +14,9 @@ module Rack
14
14
  # The filename, *not* including the path, of the "uploaded" file
15
15
  attr_reader :original_filename
16
16
 
17
+ # The tempfile
18
+ attr_reader :tempfile
19
+
17
20
  # The content type of the "uploaded" file
18
21
  attr_accessor :content_type
19
22
 
@@ -57,9 +57,12 @@ module Rack
57
57
  value.map do |v|
58
58
 
59
59
  if (v.is_a?(Hash))
60
+ nested_params = {}
60
61
  build_multipart(v, false).each { |subkey, subvalue|
61
- flattened_params["#{k}[]#{subkey}"] = subvalue
62
+ nested_params[subkey] = subvalue
62
63
  }
64
+ flattened_params["#{k}[]"] ||= []
65
+ flattened_params["#{k}[]"] << nested_params
63
66
  else
64
67
  flattened_params["#{k}[]"] = value
65
68
  end
@@ -85,21 +88,32 @@ module Rack
85
88
 
86
89
  private
87
90
  def build_parts(parameters)
91
+ get_parts(parameters).join + "--#{MULTIPART_BOUNDARY}--\r"
92
+ end
93
+
94
+ def get_parts(parameters)
88
95
  parameters.map { |name, value|
89
- if value.respond_to?(:original_filename)
90
- build_file_part(name, value)
96
+ if name =~ /\[\]\Z/ && value.is_a?(Array) && value.all? {|v| v.is_a?(Hash)}
97
+ value.map { |hash|
98
+ new_value = {}
99
+ hash.each { |k, v| new_value[name+k] = v }
100
+ get_parts(new_value).join
101
+ }.join
102
+ else
103
+ if value.respond_to?(:original_filename)
104
+ build_file_part(name, value)
91
105
 
92
- elsif value.is_a?(Array) and value.all? { |v| v.respond_to?(:original_filename) }
93
- value.map do |v|
94
- build_file_part(name, v)
95
- end.join
106
+ elsif value.is_a?(Array) and value.all? { |v| v.respond_to?(:original_filename) }
107
+ value.map do |v|
108
+ build_file_part(name, v)
109
+ end.join
96
110
 
97
- else
98
- primitive_part = build_primitive_part(name, value)
99
- Rack::Test.encoding_aware_strings? ? primitive_part.force_encoding('BINARY') : primitive_part
111
+ else
112
+ primitive_part = build_primitive_part(name, value)
113
+ Rack::Test.encoding_aware_strings? ? primitive_part.force_encoding('BINARY') : primitive_part
114
+ end
100
115
  end
101
-
102
- }.join + "--#{MULTIPART_BOUNDARY}--\r"
116
+ }
103
117
  end
104
118
 
105
119
  def build_primitive_part(parameter_name, value)
@@ -2,11 +2,11 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = "rack-test"
5
- s.version = "0.6.2"
5
+ s.version = "0.6.3"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Bryan Helmkamp"]
9
- s.date = "2012-09-27"
9
+ s.date = "2015-01-09"
10
10
  s.description = "Rack::Test is a small, simple testing API for Rack apps. It can be used on its\nown or as a reusable starting point for Web frameworks and testing libraries\nto build on. Most of its initial functionality is an extraction of Merb 1.0's\nrequest helpers feature."
11
11
  s.email = "bryan@brynary.com"
12
12
  s.extra_rdoc_files = [
@@ -17,6 +17,8 @@ describe Rack::Test::UploadedFile do
17
17
  uploaded_file.should respond_to(:size)
18
18
  uploaded_file.should respond_to(:unlink)
19
19
  uploaded_file.should respond_to(:read)
20
+ uploaded_file.should respond_to(:original_filename)
21
+ uploaded_file.should respond_to(:tempfile) # Allows calls to params[:file].tempfile
20
22
  end
21
23
 
22
24
  end
@@ -104,6 +104,77 @@ describe Rack::Test::Utils do
104
104
  check params["foo"].should == ["1", "2"]
105
105
  end
106
106
 
107
+ it "builds nested multipart bodies with an array of hashes" do
108
+ files = Rack::Test::UploadedFile.new(multipart_file("foo.txt"))
109
+ data = build_multipart("files" => files, "foo" => [{"id" => "1", "name" => 'Dave'}, {"id" => "2", "name" => 'Steve'}])
110
+
111
+ options = {
112
+ "CONTENT_TYPE" => "multipart/form-data; boundary=#{Rack::Test::MULTIPART_BOUNDARY}",
113
+ "CONTENT_LENGTH" => data.length.to_s,
114
+ :input => StringIO.new(data)
115
+ }
116
+ env = Rack::MockRequest.env_for("/", options)
117
+ params = Rack::Utils::Multipart.parse_multipart(env)
118
+ check params["files"][:filename].should == "foo.txt"
119
+ params["files"][:tempfile].read.should == "bar\n"
120
+ check params["foo"].should == [{"id" => "1", "name" => "Dave"}, {"id" => "2", "name" => "Steve"}]
121
+ end
122
+
123
+ it "builds nested multipart bodies with arbitrarily nested array of hashes" do
124
+ files = Rack::Test::UploadedFile.new(multipart_file("foo.txt"))
125
+ data = build_multipart("files" => files, "foo" => {"bar" => [{"id" => "1", "name" => 'Dave'},
126
+ {"id" => "2", "name" => 'Steve', "qux" => [{"id" => '3', "name" => 'mike'},
127
+ {"id" => '4', "name" => 'Joan'}]}]})
128
+
129
+ options = {
130
+ "CONTENT_TYPE" => "multipart/form-data; boundary=#{Rack::Test::MULTIPART_BOUNDARY}",
131
+ "CONTENT_LENGTH" => data.length.to_s,
132
+ :input => StringIO.new(data)
133
+ }
134
+ env = Rack::MockRequest.env_for("/", options)
135
+ params = Rack::Utils::Multipart.parse_multipart(env)
136
+ check params["files"][:filename].should == "foo.txt"
137
+ params["files"][:tempfile].read.should == "bar\n"
138
+ check params["foo"].should == {"bar" => [{"id" => "1", "name" => "Dave"},
139
+ {"id" => "2", "name" => "Steve", "qux" => [{"id" => '3', "name" => 'mike'},
140
+ {"id" => '4', "name" => 'Joan'}]}]}
141
+ end
142
+
143
+ it 'does not break with params that look nested, but are not' do
144
+ files = Rack::Test::UploadedFile.new(multipart_file("foo.txt"))
145
+ data = build_multipart("foo[]" => "1", "bar[]" => {"qux" => "2"}, "files[]" => files)
146
+
147
+ options = {
148
+ "CONTENT_TYPE" => "multipart/form-data; boundary=#{Rack::Test::MULTIPART_BOUNDARY}",
149
+ "CONTENT_LENGTH" => data.length.to_s,
150
+ :input => StringIO.new(data)
151
+ }
152
+ env = Rack::MockRequest.env_for("/", options)
153
+ params = Rack::Utils::Multipart.parse_multipart(env)
154
+ check params["files"][0][:filename].should == "foo.txt"
155
+ params["files"][0][:tempfile].read.should == "bar\n"
156
+ check params["foo"][0].should == "1"
157
+ check params["bar"][0].should == {"qux" => "2"}
158
+ end
159
+
160
+ it 'allows for nested files' do
161
+ files = Rack::Test::UploadedFile.new(multipart_file("foo.txt"))
162
+ data = build_multipart("foo" => [{"id" => "1", "data" => files},
163
+ {"id" => "2", "data" => ["3", "4"]}])
164
+
165
+ options = {
166
+ "CONTENT_TYPE" => "multipart/form-data; boundary=#{Rack::Test::MULTIPART_BOUNDARY}",
167
+ "CONTENT_LENGTH" => data.length.to_s,
168
+ :input => StringIO.new(data)
169
+ }
170
+ env = Rack::MockRequest.env_for("/", options)
171
+ params = Rack::Utils::Multipart.parse_multipart(env)
172
+ check params["foo"][0]["id"].should == "1"
173
+ check params["foo"][0]["data"][:filename].should == "foo.txt"
174
+ params["foo"][0]["data"][:tempfile].read.should == "bar\n"
175
+ check params["foo"][1].should == {"id" => "2", "data" => ["3", "4"]}
176
+ end
177
+
107
178
  it "returns nil if no UploadedFiles were used" do
108
179
  data = build_multipart("people" => [{"submit-name" => "Larry", "files" => "contents"}])
109
180
  data.should be_nil
@@ -123,8 +123,8 @@ describe Rack::Test::Session do
123
123
  end
124
124
 
125
125
  it "does not rewrite a GET query string when :params is not supplied" do
126
- request "/foo?a=1&b=2&c=3&e=4&d=5"
127
- last_request.query_string.should == "a=1&b=2&c=3&e=4&d=5"
126
+ request "/foo?a=1&b=2&c=3&e=4&d=5+%20"
127
+ last_request.query_string.should == "a=1&b=2&c=3&e=4&d=5+%20"
128
128
  end
129
129
 
130
130
  it "accepts params and builds url encoded params for POST requests" do
@@ -289,6 +289,46 @@ describe Rack::Test::Session do
289
289
  end
290
290
  end
291
291
 
292
+ describe "#env" do
293
+ it "sets the env to be sent with requests" do
294
+ env "rack.session", {:csrf => 'token'}
295
+ request "/"
296
+
297
+ last_request.env["rack.session"].should == {:csrf => 'token'}
298
+ end
299
+
300
+ it "persists across multiple requests" do
301
+ env "rack.session", {:csrf => 'token'}
302
+ request "/"
303
+ request "/"
304
+
305
+ last_request.env["rack.session"].should == {:csrf => 'token'}
306
+ end
307
+
308
+ it "overwrites previously set envs" do
309
+ env "rack.session", {:csrf => 'token'}
310
+ env "rack.session", {:some => :thing}
311
+ request "/"
312
+
313
+ last_request.env["rack.session"].should == {:some => :thing}
314
+ end
315
+
316
+ it "can be used to clear a env" do
317
+ env "rack.session", {:csrf => 'token'}
318
+ env "rack.session", nil
319
+ request "/"
320
+
321
+ last_request.env.should_not have_key("X_CSRF_TOKEN")
322
+ end
323
+
324
+ it "is overridden by envs sent during the request" do
325
+ env "rack.session", {:csrf => 'token'}
326
+ request "/", "rack.session" => {:some => :thing}
327
+
328
+ last_request.env["rack.session"].should == {:some => :thing}
329
+ end
330
+ end
331
+
292
332
  describe "#authorize" do
293
333
  it "sets the HTTP_AUTHORIZATION header" do
294
334
  authorize "bryan", "secret"
@@ -1,6 +1,9 @@
1
1
  require "rubygems"
2
2
  require "bundler/setup"
3
3
 
4
+ require "codeclimate-test-reporter"
5
+ CodeClimate::TestReporter.start
6
+
4
7
  require "rack"
5
8
  require "rspec"
6
9
 
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.6.2
4
+ version: 0.6.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-09-27 00:00:00.000000000 Z
12
+ date: 2015-01-09 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rack
@@ -92,7 +92,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
92
92
  version: '0'
93
93
  requirements: []
94
94
  rubyforge_project: rack-test
95
- rubygems_version: 1.8.23
95
+ rubygems_version: 1.8.23.2
96
96
  signing_key:
97
97
  specification_version: 3
98
98
  summary: Simple testing API built on Rack