diff options
Diffstat (limited to 'test/spec_mock_response.rb')
-rw-r--r-- | test/spec_mock_response.rb | 276 |
1 files changed, 276 insertions, 0 deletions
diff --git a/test/spec_mock_response.rb b/test/spec_mock_response.rb new file mode 100644 index 00000000..2813ecd6 --- /dev/null +++ b/test/spec_mock_response.rb @@ -0,0 +1,276 @@ +# frozen_string_literal: true + +require_relative 'helper' +require 'yaml' +require_relative 'psych_fix' + +separate_testing do + require_relative '../lib/rack/mock_request' + require_relative '../lib/rack/mock_response' + require_relative '../lib/rack/lint' + require_relative '../lib/rack/request' +end + +app = Rack::Lint.new(lambda { |env| + req = Rack::Request.new(env) + + env["mock.postdata"] = env["rack.input"].read + if req.GET["error"] + env["rack.errors"].puts req.GET["error"] + env["rack.errors"].flush + end + + body = req.head? ? "" : env.to_yaml + response = Rack::Response.new( + body, + req.GET["status"] || 200, + "content-type" => "text/yaml" + ) + response.set_cookie("session_test", { value: "session_test", domain: ".test.com", path: "/" }) + response.set_cookie("secure_test", { value: "secure_test", domain: ".test.com", path: "/", secure: true }) + response.set_cookie("persistent_test", { value: "persistent_test", max_age: 15552000, path: "/" }) + response.set_cookie("persistent_with_expires_test", { value: "persistent_with_expires_test", expires: Time.httpdate("Thu, 31 Oct 2021 07:28:00 GMT"), path: "/" }) + response.set_cookie("expires_and_max-age_test", { value: "expires_and_max-age_test", expires: Time.now + 15552000 * 2, max_age: 15552000, path: "/" }) + response.finish +}) + +describe Rack::MockResponse do + it 'has standard constructor' do + headers = { "header" => "value" } + body = ["body"] + + response = Rack::MockResponse[200, headers, body] + + response.status.must_equal 200 + response.headers.must_equal headers + response.body.must_equal body.join + end + + it "provide access to the HTTP status" do + res = Rack::MockRequest.new(app).get("") + res.must_be :successful? + res.must_be :ok? + + res = Rack::MockRequest.new(app).get("/?status=404") + res.wont_be :successful? + res.must_be :client_error? + res.must_be :not_found? + + res = Rack::MockRequest.new(app).get("/?status=501") + res.wont_be :successful? + res.must_be :server_error? + + res = Rack::MockRequest.new(app).get("/?status=307") + res.must_be :redirect? + + res = Rack::MockRequest.new(app).get("/?status=201", lint: true) + res.must_be :empty? + end + + it "provide access to the HTTP headers" do + res = Rack::MockRequest.new(app).get("") + res.must_include "content-type" + res.headers["content-type"].must_equal "text/yaml" + res.original_headers["content-type"].must_equal "text/yaml" + res["content-type"].must_equal "text/yaml" + res.content_type.must_equal "text/yaml" + res.content_length.wont_equal 0 + res.location.must_be_nil + end + + it "provide access to session cookies" do + res = Rack::MockRequest.new(app).get("") + session_cookie = res.cookie("session_test") + session_cookie.value[0].must_equal "session_test" + session_cookie.domain.must_equal ".test.com" + session_cookie.path.must_equal "/" + session_cookie.secure.must_equal false + session_cookie.expires.must_be_nil + end + + it "provides access to persistent cookies set with max-age" do + res = Rack::MockRequest.new(app).get("") + persistent_cookie = res.cookie("persistent_test") + persistent_cookie.value[0].must_equal "persistent_test" + persistent_cookie.domain.must_be_nil + persistent_cookie.path.must_equal "/" + persistent_cookie.secure.must_equal false + persistent_cookie.expires.wont_be_nil + persistent_cookie.expires.must_be :<, (Time.now + 15552000) + end + + it "provides access to persistent cookies set with expires" do + res = Rack::MockRequest.new(app).get("") + persistent_cookie = res.cookie("persistent_with_expires_test") + persistent_cookie.value[0].must_equal "persistent_with_expires_test" + persistent_cookie.domain.must_be_nil + persistent_cookie.path.must_equal "/" + persistent_cookie.secure.must_equal false + persistent_cookie.expires.wont_be_nil + persistent_cookie.expires.must_equal Time.httpdate("Thu, 31 Oct 2021 07:28:00 GMT") + end + + it "parses cookies giving max-age precedence over expires" do + res = Rack::MockRequest.new(app).get("") + persistent_cookie = res.cookie("expires_and_max-age_test") + persistent_cookie.value[0].must_equal "expires_and_max-age_test" + persistent_cookie.expires.wont_be_nil + persistent_cookie.expires.must_be :<, (Time.now + 15552000) + end + + it "provide access to secure cookies" do + res = Rack::MockRequest.new(app).get("") + secure_cookie = res.cookie("secure_test") + secure_cookie.value[0].must_equal "secure_test" + secure_cookie.domain.must_equal ".test.com" + secure_cookie.path.must_equal "/" + secure_cookie.secure.must_equal true + secure_cookie.expires.must_be_nil + end + + it "parses cookie headers with equals sign at the end" do + res = Rack::MockRequest.new(->(env) { [200, { "Set-Cookie" => "__cf_bm=_somebase64encodedstringwithequalsatthened=; array=awesome" }, [""]] }).get("") + cookie = res.cookie("__cf_bm") + cookie.value[0].must_equal "_somebase64encodedstringwithequalsatthened=" + end + + it "return nil if a non existent cookie is requested" do + res = Rack::MockRequest.new(app).get("") + res.cookie("i_dont_exist").must_be_nil + end + + deprecated "parses cookie headers provided as an array" do + res = Rack::MockRequest.new(->(env) { [200, [["set-cookie", "array=awesome"]], [""]] }).get("") + array_cookie = res.cookie("array") + array_cookie.value[0].must_equal "awesome" + end + + deprecated "parses multiple set-cookie headers provided as an array" do + cookie_headers = [["set-cookie", "array=awesome\nmultiple=times"]] + res = Rack::MockRequest.new(->(env) { [200, cookie_headers, [""]] }).get("") + array_cookie = res.cookie("array") + array_cookie.value[0].must_equal "awesome" + second_cookie = res.cookie("multiple") + second_cookie.value[0].must_equal "times" + end + + it "parses multiple set-cookie headers provided as hash with array value" do + cookie_headers = { "set-cookie" => ["array=awesome", "multiple=times"]} + res = Rack::MockRequest.new(->(env) { [200, cookie_headers, [""]] }).get("") + array_cookie = res.cookie("array") + array_cookie.value[0].must_equal "awesome" + second_cookie = res.cookie("multiple") + second_cookie.value[0].must_equal "times" + end + + it "provide access to the HTTP body" do + res = Rack::MockRequest.new(app).get("") + res.body.must_match(/rack/) + assert_match(res, /rack/) + + res.match('rack')[0].must_equal 'rack' + res.match('banana').must_be_nil + end + + it "provide access to the Rack errors" do + res = Rack::MockRequest.new(app).get("/?error=foo", lint: true) + res.must_be :ok? + res.errors.wont_be :empty? + res.errors.must_include "foo" + end + + deprecated "handle enumerable headers that are not a hash" do + # this is exactly what rack-test does + res = Rack::MockResponse.new(200, [], []) + res.cookies.must_equal({}) + end + + it "allow calling body.close afterwards" do + # this is exactly what rack-test does + body = StringIO.new("hi") + res = Rack::MockResponse.new(200, {}, body) + body.close if body.respond_to?(:close) + 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) + }.must_raise Rack::MockRequest::FatalWarning + + lambda { + Rack::MockRequest.new(lambda { |env| env['rack.errors'].write(env['rack.errors'].string) }).get("/", fatal: true) + }.must_raise(Rack::MockRequest::FatalWarning).message.must_equal '' + end +end + +describe Rack::MockResponse, 'headers' do + before do + @res = Rack::MockRequest.new(app).get('') + @res.set_header 'FOO', '1' + end + + it 'has_header?' do + lambda { @res.has_header? nil }.must_raise ArgumentError + + @res.has_header?('FOO').must_equal true + @res.has_header?('Foo').must_equal true + end + + it 'get_header' do + lambda { @res.get_header nil }.must_raise ArgumentError + + @res.get_header('FOO').must_equal '1' + @res.get_header('Foo').must_equal '1' + end + + it 'set_header' do + lambda { @res.set_header nil, '1' }.must_raise ArgumentError + + @res.set_header('FOO', '2').must_equal '2' + @res.get_header('FOO').must_equal '2' + + @res.set_header('Foo', '3').must_equal '3' + @res.get_header('Foo').must_equal '3' + @res.get_header('FOO').must_equal '3' + + @res.set_header('FOO', nil).must_be_nil + @res.get_header('FOO').must_be_nil + @res.has_header?('FOO').must_equal true + end + + it 'add_header' do + lambda { @res.add_header nil, '1' }.must_raise ArgumentError + + # Sets header on first addition + @res.add_header('FOO', '1').must_equal ['1', '1'] + @res.get_header('FOO').must_equal ['1', '1'] + + # Ignores nil additions + @res.add_header('FOO', nil).must_equal ['1', '1'] + @res.get_header('FOO').must_equal ['1', '1'] + + # Converts additions to strings + @res.add_header('FOO', 2).must_equal ['1', '1', '2'] + @res.get_header('FOO').must_equal ['1', '1', '2'] + + # Respects underlying case-sensitivity + @res.add_header('Foo', 'yep').must_equal ['1', '1', '2', 'yep'] + @res.get_header('Foo').must_equal ['1', '1', '2', 'yep'] + @res.get_header('FOO').must_equal ['1', '1', '2', 'yep'] + end + + it 'delete_header' do + lambda { @res.delete_header nil }.must_raise ArgumentError + + @res.delete_header('FOO').must_equal '1' + @res.has_header?('FOO').must_equal false + + @res.has_header?('Foo').must_equal false + @res.delete_header('Foo').must_be_nil + end +end |