diff options
author | Jeremy Evans <code@jeremyevans.net> | 2022-05-10 11:06:01 -0700 |
---|---|---|
committer | Jeremy Evans <code@jeremyevans.net> | 2022-05-25 08:33:11 -0700 |
commit | 214023ea7745018125fcad43edc9ff8b6cfb209a (patch) | |
tree | 184d7181028714ba513661938590cfee13788002 | |
parent | f7e05d530ca306d2d730671765d88587c75b4741 (diff) | |
download | rack-214023ea7745018125fcad43edc9ff8b6cfb209a.tar.gz |
Add remaining tests for 100% branch coverage
Coverage after this commit:
3273 relevant lines, 3273 lines covered and 0 lines missed. ( 100.0% )
1083 total branches, 1083 branches covered and 0 branches missed. ( 100.0% )
-rw-r--r-- | test/multipart/content_type_and_unknown_charset | 6 | ||||
-rw-r--r-- | test/spec_auth_digest.rb | 5 | ||||
-rw-r--r-- | test/spec_chunked.rb | 16 | ||||
-rw-r--r-- | test/spec_common_logger.rb | 4 | ||||
-rw-r--r-- | test/spec_conditional_get.rb | 27 | ||||
-rw-r--r-- | test/spec_directory.rb | 24 | ||||
-rw-r--r-- | test/spec_etag.rb | 6 | ||||
-rw-r--r-- | test/spec_files.rb | 14 | ||||
-rwxr-xr-x | test/spec_headers.rb | 1 | ||||
-rw-r--r-- | test/spec_mock.rb | 11 | ||||
-rw-r--r-- | test/spec_multipart.rb | 24 | ||||
-rw-r--r-- | test/spec_rewindable_input.rb | 19 | ||||
-rw-r--r-- | test/spec_sendfile.rb | 13 | ||||
-rw-r--r-- | test/spec_static.rb | 8 | ||||
-rw-r--r-- | test/spec_tempfile_reaper.rb | 16 | ||||
-rw-r--r-- | test/spec_urlmap.rb | 5 |
16 files changed, 191 insertions, 8 deletions
diff --git a/test/multipart/content_type_and_unknown_charset b/test/multipart/content_type_and_unknown_charset new file mode 100644 index 00000000..cf9c14c7 --- /dev/null +++ b/test/multipart/content_type_and_unknown_charset @@ -0,0 +1,6 @@ +--AaB03x
+content-disposition: form-data; name="text"
+content-type: text/plain; charset=foo; bar=baz
+
+contents
+--AaB03x--
diff --git a/test/spec_auth_digest.rb b/test/spec_auth_digest.rb index e428375c..95df9c1b 100644 --- a/test/spec_auth_digest.rb +++ b/test/spec_auth_digest.rb @@ -273,6 +273,7 @@ describe Rack::Auth::Digest::MD5 do req.respond_to?(:nonce).must_equal true req.respond_to?(:a).must_equal true req.a.must_equal 'b' + proc{req.missing}.must_raise NoMethodError lambda { req.a(2) }.must_raise ArgumentError end @@ -280,4 +281,8 @@ describe Rack::Auth::Digest::MD5 do Rack::Auth::Digest::Nonce.new.fresh?.must_equal true Rack::Auth::Digest::Nonce.new.stale?.must_equal false end + + it 'Params.new can be called without a block' do + Rack::Auth::Digest::Params.new.must_be_instance_of(Rack::Auth::Digest::Params) + end end diff --git a/test/spec_chunked.rb b/test/spec_chunked.rb index ec3e4fb2..933a0817 100644 --- a/test/spec_chunked.rb +++ b/test/spec_chunked.rb @@ -52,6 +52,22 @@ describe Rack::Chunked do response.body.must_equal "5\r\nHello\r\n1\r\n \r\n6\r\nWorld!\r\n0\r\n\r\n" end + it 'avoid empty chunks' do + app = lambda { |env| [200, { "content-type" => "text/plain" }, ['Hello', '', 'World!']] } + response = Rack::MockResponse.new(*chunked(app).call(@env)) + response.headers.wont_include 'content-length' + response.headers['transfer-encoding'].must_equal 'chunked' + response.body.must_equal "5\r\nHello\r\n6\r\nWorld!\r\n0\r\n\r\n" + end + + it 'handles unclosable bodies' do + app = lambda { |env| [200, { "content-type" => "text/plain" }, ['Hello', '', 'World!']] } + response = Rack::MockResponse.new(*Rack::Chunked.new(app).call(@env)) + response.headers.wont_include 'content-length' + response.headers['transfer-encoding'].must_equal 'chunked' + response.body.must_equal "5\r\nHello\r\n6\r\nWorld!\r\n0\r\n\r\n" + end + it 'chunks empty bodies properly' do app = lambda { |env| [200, { "content-type" => "text/plain" }, []] } response = Rack::MockResponse.new(*chunked(app).call(@env)) diff --git a/test/spec_common_logger.rb b/test/spec_common_logger.rb index 09995dda..56495e6c 100644 --- a/test/spec_common_logger.rb +++ b/test/spec_common_logger.rb @@ -91,10 +91,10 @@ describe Rack::CommonLogger do it "log in common log format" do log = StringIO.new with_mock_time do - Rack::MockRequest.new(Rack::CommonLogger.new(app, log)).get("/") + Rack::MockRequest.new(Rack::CommonLogger.new(app, log)).get("/", 'QUERY_STRING' => 'foo=bar') end - md = /- - - \[([^\]]+)\] "(\w+) \/ HTTP\/1\.1" (\d{3}) \d+ ([\d\.]+)/.match(log.string) + md = /- - - \[([^\]]+)\] "(\w+) \/\?foo=bar HTTP\/1\.1" (\d{3}) \d+ ([\d\.]+)/.match(log.string) md.wont_equal nil time, method, status, duration = *md.captures time.must_equal Time.at(0).strftime("%d/%b/%Y:%H:%M:%S %z") diff --git a/test/spec_conditional_get.rb b/test/spec_conditional_get.rb index 36da7412..8811bb27 100644 --- a/test/spec_conditional_get.rb +++ b/test/spec_conditional_get.rb @@ -37,6 +37,22 @@ describe Rack::ConditionalGet do response.body.must_be :empty? end + it "closes bodies" do + body = Object.new + def body.each; yield 'TEST' end + closed = false + body.define_singleton_method(:close){closed = true} + app = conditional_get(lambda { |env| + [200, { 'last-modified' => (Time.now - 3600).httpdate }, body] }) + + response = Rack::MockRequest.new(app). + get("/", 'HTTP_IF_MODIFIED_SINCE' => Time.now.httpdate) + + response.status.must_equal 304 + response.body.must_be :empty? + closed.must_equal true + end + it "set a 304 status and truncate body when if-none-match hits" do app = conditional_get(lambda { |env| [200, { 'etag' => '1234' }, ['TEST']] }) @@ -59,6 +75,17 @@ describe Rack::ConditionalGet do response.body.must_be :empty? end + it "not set a 304 status if last-modified is too short" do + app = conditional_get(lambda { |env| + [200, { 'last-modified' => '1234', 'content-type' => 'text/plain' }, ['TEST']] }) + + response = Rack::MockRequest.new(app). + get("/", 'HTTP_IF_MODIFIED_SINCE' => Time.now.httpdate) + + response.status.must_equal 200 + response.body.must_equal 'TEST' + end + it "not set a 304 status if if-modified-since hits but etag does not" do timestamp = Time.now.httpdate app = conditional_get(lambda { |env| diff --git a/test/spec_directory.rb b/test/spec_directory.rb index d7e90333..4e5db0e8 100644 --- a/test/spec_directory.rb +++ b/test/spec_directory.rb @@ -40,12 +40,34 @@ describe Rack::Directory do end end + it "serve root directory index" do + res = Rack::MockRequest.new(Rack::Lint.new(app)). + get("/") + + res.must_be :ok? + assert_includes(res.body, '<html><head>') + assert_includes(res.body, "href='cgi") + end + it "serve directory indices" do res = Rack::MockRequest.new(Rack::Lint.new(app)). get("/cgi/") res.must_be :ok? - assert_match(res, /<html><head>/) + assert_includes(res.body, '<html><head>') + assert_includes(res.body, "rackup_stub.rb") + end + + it "return 404 for pipes" do + begin + File.mkfifo('test/cgi/fifo') + res = Rack::MockRequest.new(Rack::Lint.new(app)). + get("/cgi/fifo") + + res.status.must_equal 404 + ensure + File.delete('test/cgi/fifo') + end end it "serve directory indices with bad symlinks" do diff --git a/test/spec_etag.rb b/test/spec_etag.rb index ecd9383f..35fab258 100644 --- a/test/spec_etag.rb +++ b/test/spec_etag.rb @@ -76,6 +76,12 @@ describe Rack::ETag do response[1]['etag'].must_be_nil end + it "set handle empty body parts" do + app = lambda { |env| [200, { 'content-type' => 'text/plain' }, ["Hello", "", ", World!"]] } + response = etag(app).call(request) + response[1]['etag'].must_equal "W/\"dffd6021bb2bd5b0af676290809ec3a5\"" + end + it "not set etag if last-modified is set" do app = lambda { |env| [200, { 'content-type' => 'text/plain', 'last-modified' => Time.now.httpdate }, ["Hello, World!"]] } response = etag(app).call(request) diff --git a/test/spec_files.rb b/test/spec_files.rb index f74e5195..b65a7cfd 100644 --- a/test/spec_files.rb +++ b/test/spec_files.rb @@ -192,6 +192,20 @@ describe Rack::Files do res.body.must_equal "IS FILE! ***" end + it "handle case where file is truncated during request" do + env = Rack::MockRequest.env_for("/cgi/test") + env["HTTP_RANGE"] = "bytes=0-3300" + files = Class.new(Rack::Files) do + def filesize(_); 10000 end + end.new(DOCROOT) + + res = Rack::MockResponse.new(*files.call(env)) + + res.status.must_equal 206 + res["content-length"].must_equal "209" + res["content-range"].must_equal "bytes 0-3300/10000" + end + it "return correct multiple byte ranges in body" do env = Rack::MockRequest.env_for("/cgi/test") env["HTTP_RANGE"] = "bytes=22-33, 60-80" diff --git a/test/spec_headers.rb b/test/spec_headers.rb index cabf00ff..dcd6296b 100755 --- a/test/spec_headers.rb +++ b/test/spec_headers.rb @@ -468,6 +468,7 @@ class RackHeadersTest < Minitest::Spec def test_slice assert_equal(Rack::Headers['Ab'=>'1', 'cD'=>'2', '3'=>'4'], @fh.slice('aB', 'Cd', '3')) assert_equal(Rack::Headers['AB'=>'1', 'CD'=>'2'], @fh.slice('Ab', 'CD')) + assert_equal(Rack::Headers[], @fh.slice('ad')) assert_equal('1', @fh.slice('AB', 'cd')['Ab']) end diff --git a/test/spec_mock.rb b/test/spec_mock.rb index 48dfde06..4bc57b18 100644 --- a/test/spec_mock.rb +++ b/test/spec_mock.rb @@ -49,6 +49,13 @@ describe Rack::MockRequest do env.must_include "rack.version" end + it "should handle a non-GET request with both :input and :params" do + env = Rack::MockRequest.env_for("/", method: :post, input: nil, params: {}) + env["PATH_INFO"].must_equal "/" + env.must_be_kind_of Hash + env['rack.input'].read.must_equal '' + end + it "return an environment with a path" do env = Rack::MockRequest.env_for("http://www.example.com/parse?location[]=1&location[]=2&age_group[]=2") env["QUERY_STRING"].must_equal "location[]=1&location[]=2&age_group[]=2" @@ -429,6 +436,10 @@ describe Rack::MockResponse do res.body.must_equal 'hi' end + it "ignores plain strings passed as errors" do + Rack::MockResponse.new(200, {}, [], 'e').errors.must_be_nil + end + it "optionally make Rack errors fatal" do lambda { Rack::MockRequest.new(app).get("/?error=foo", fatal: true) diff --git a/test/spec_multipart.rb b/test/spec_multipart.rb index 8e4a0c4c..12065aa1 100644 --- a/test/spec_multipart.rb +++ b/test/spec_multipart.rb @@ -527,6 +527,15 @@ content-type: image/jpeg\r files[:tempfile].read.must_equal "contents" end + it "raises RuntimeError for invalid file path" do + proc{Rack::Multipart::UploadedFile.new('non-existant')}.must_raise RuntimeError + end + + it "supports uploading files in binary mode" do + Rack::Multipart::UploadedFile.new(multipart_file("file1.txt")).wont_be :binmode? + Rack::Multipart::UploadedFile.new(multipart_file("file1.txt"), binary: true).must_be :binmode? + end + it "builds multipart body" do files = Rack::Multipart::UploadedFile.new(multipart_file("file1.txt")) data = Rack::Multipart.build_multipart("submit-name" => "Larry", "files" => files) @@ -660,6 +669,21 @@ content-type: image/jpeg\r end end + it "treat a multipart limit of 0 as no limit" do + begin + previous_limit = Rack::Utils.multipart_part_limit + Rack::Utils.multipart_part_limit = 0 + + env = Rack::MockRequest.env_for '/', multipart_fixture(:three_files_three_fields) + params = Rack::Multipart.parse_multipart(env) + params['reply'].must_equal 'yes' + params['to'].must_equal 'people' + params['from'].must_equal 'others' + ensure + Rack::Utils.multipart_part_limit = previous_limit + end + end + it "reach a multipart limit" do begin previous_limit = Rack::Utils.multipart_part_limit diff --git a/test/spec_rewindable_input.rb b/test/spec_rewindable_input.rb index e672bcbb..603afbda 100644 --- a/test/spec_rewindable_input.rb +++ b/test/spec_rewindable_input.rb @@ -13,10 +13,6 @@ module RewindableTest @rio = Rack::RewindableInput.new(@io) end - class << self # HACK to get this running w/ as few changes as possible - alias_method :should, :it - end - it "be able to handle to read()" do @rio.read.must_equal "hello world" end @@ -44,17 +40,23 @@ module RewindableTest end it "rewind to the beginning when #rewind is called" do - @rio.read(1) + @rio.rewind + @rio.read(1).must_equal 'h' @rio.rewind @rio.read.must_equal "hello world" end it "be able to handle gets" do @rio.gets.must_equal "hello world" + @rio.rewind + @rio.gets.must_equal "hello world" end it "be able to handle size" do @rio.size.must_equal "hello world".size + @rio.size.must_equal "hello world".size + @rio.rewind + @rio.gets.must_equal "hello world" end it "be able to handle each" do @@ -63,6 +65,13 @@ module RewindableTest array << data end array.must_equal ["hello world"] + + @rio.rewind + array = [] + @rio.each do |data| + array << data + end + array.must_equal ["hello world"] end it "not buffer into a Tempfile if no data has been read yet" do diff --git a/test/spec_sendfile.rb b/test/spec_sendfile.rb index ee6f222a..c0ef5e5d 100644 --- a/test/spec_sendfile.rb +++ b/test/spec_sendfile.rb @@ -67,6 +67,19 @@ describe Rack::Sendfile do end end + it "closes body when x-sendfile used" do + body = sendfile_body + closed = false + body.define_singleton_method(:close){closed = true} + request({'HTTP_X_SENDFILE_TYPE' => 'x-sendfile'}, body) do |response| + response.must_be :ok? + response.body.must_be :empty? + response.headers['content-length'].must_equal '0' + response.headers['x-sendfile'].must_equal File.join(Dir.tmpdir, "rack_sendfile") + end + closed.must_equal true + end + it "sets x-lighttpd-send-file response header and discards body" do request 'HTTP_X_SENDFILE_TYPE' => 'x-lighttpd-send-file' do |response| response.must_be :ok? diff --git a/test/spec_static.rb b/test/spec_static.rb index e102ded6..9cc33a42 100644 --- a/test/spec_static.rb +++ b/test/spec_static.rb @@ -151,6 +151,14 @@ describe Rack::Static do res.headers['content-type'].must_be_nil end + it "return 304 if gzipped file isn't modified since last serve" do + path = File.join(DOCROOT, "/cgi/test") + res = @gzip_request.get("/cgi/test", 'HTTP_IF_MODIFIED_SINCE' => File.mtime(path+'.gz').httpdate, 'HTTP_ACCEPT_ENCODING' => 'deflate, gzip') + + res.status.must_equal 304 + res.body.must_be :empty? + end + it "supports serving fixed cache-control (legacy option)" do opts = OPTIONS.merge(cache_control: 'public') request = Rack::MockRequest.new(static(DummyApp.new, opts)) diff --git a/test/spec_tempfile_reaper.rb b/test/spec_tempfile_reaper.rb index ce5d2c76..7e5c6790 100644 --- a/test/spec_tempfile_reaper.rb +++ b/test/spec_tempfile_reaper.rb @@ -84,4 +84,20 @@ describe Rack::TempfileReaper do tempfile1.closed.must_equal true tempfile2.closed.must_equal true end + + it 'handle missing rack.tempfiles on normal response' do + app = lambda do |env| + env.delete('rack.tempfiles') + [200, {}, ['Hello, World!']] + end + call(app)[2].close + end + + it 'handle missing rack.tempfiles on error' do + app = lambda do |env| + env.delete('rack.tempfiles') + raise 'Foo' + end + proc{call(app)}.must_raise RuntimeError + end end diff --git a/test/spec_urlmap.rb b/test/spec_urlmap.rb index 855e4541..e11c4e6d 100644 --- a/test/spec_urlmap.rb +++ b/test/spec_urlmap.rb @@ -44,6 +44,11 @@ describe Rack::URLMap do res["x-scriptname"].must_equal "/foo/bar" res["x-pathinfo"].must_equal "" + res = Rack::MockRequest.new(map).get("/foo/bard") + res.must_be :ok? + res["x-scriptname"].must_equal "/foo" + res["x-pathinfo"].must_equal "/bard" + res = Rack::MockRequest.new(map).get("/foo/bar/") res.must_be :ok? res["x-scriptname"].must_equal "/foo/bar" |