"localhost", "HTTP_ACCEPT" => "application/json", "HTTP_CONTENT_TYPE" => "application/x-www-form-urlencoded", "QUERY_STRING" => "guinea_pig=Claude&hamster=Fizzgig" ]; $_COOKIE = [ "cat" => "Molly" ]; $_FILES = []; $_POST = [ "dog" => "Bear" ]; $attributes = ["guinea_pig" => "Claude"]; $request = ServerRequest::getServerRequest($attributes); $this->assertNotNull($request); return $request; } // ------------------------------------------------------------------------ // Marshalling Request Information /** * @backupGlobals enabled * @dataProvider protocolVersionProvider */ public function testGetServerRequestReadsProtocolVersion($expectedProtocol, $serverProtocol) { $_SERVER = [ "HTTP_HOST" => "localhost", "SERVER_PROTOCOL" => $serverProtocol, "REQUEST_METHOD" => "GET" ]; $request = ServerRequest::getServerRequest(); $this->assertEquals($expectedProtocol, $request->getProtocolVersion()); } public function protocolVersionProvider() { return [ ["1.1", "HTTP/1.1"], ["1.0", "HTTP/1.0"], ["1.1", null], ["1.1", "INVALID"] ]; } /** * @backupGlobals enabled * @dataProvider methodProvider */ public function testGetServerRequestReadsMethod($expectedMethod, $serverMethod) { $_SERVER = [ "HTTP_HOST" => "localhost", "REQUEST_METHOD" => $serverMethod ]; $request = ServerRequest::getServerRequest(); $this->assertEquals($expectedMethod, $request->getMethod()); } public function methodProvider() { return [ ["GET", "GET"], ["POST", "POST"], ["DELETE", "DELETE"], ["PUT", "PUT"], ["OPTIONS", "OPTIONS"], ["GET", null] ]; } /** * @backupGlobals enabled * @dataProvider requestTargetProvider */ public function testGetServerRequestReadsRequestTargetFromRequest($expectedRequestTarget, $serverRequestUri) { $_SERVER = [ "HTTP_HOST" => "localhost", "REQUEST_URI" => $serverRequestUri ]; $request = ServerRequest::getServerRequest(); $this->assertEquals($expectedRequestTarget, $request->getRequestTarget()); } public function requestTargetProvider() { return [ ["/", "/"], ["/hello", "/hello"], ["/my/path.txt", "/my/path.txt"], ["/", null] ]; } /** @depends testGetServerRequestReadsFromRequest */ public function testGetServerRequestReadsHeaders($request) { /** @var ServerRequest $request */ $this->assertEquals(["application/json"], $request->getHeader("Accept")); } /** * @backupGlobals enabled */ public function testGetServerRequestReadsContentHeaders() { $_SERVER = [ "CONTENT_LENGTH" => "1024", "CONTENT_TYPE" => "application/json" ]; $request = ServerRequest::getServerRequest(); $this->assertEquals("1024", $request->getHeaderLine("Content-length")); $this->assertEquals("application/json", $request->getHeaderLine("Content-type")); } public function testGetServerRequestReadsBody() { $body = new NullStream(); $request = $this->getMockBuilder('WellRESTed\Message\ServerRequest') ->setMethods(["getStreamForBody"]) ->getMock(); $request->expects($this->any()) ->method("getStreamForBody") ->will($this->returnValue($body)); $called = false; $callReadFromServerRequest = function () use (&$called) { $called = true; $this->readFromServerRequest(); }; $callReadFromServerRequest = $callReadFromServerRequest->bindTo($request, $request); $callReadFromServerRequest(); $this->assertSame($body, $request->getBody()); } /** * @backupGlobals enabled * @dataProvider uriProvider */ public function testGetServerRequestReadsUri($expected, $server) { $_SERVER = $server; $request = ServerRequest::getServerRequest(); $this->assertEquals($expected, $request->getUri()); } public function uriProvider() { return [ [ new Uri("http://localhost/path"), [ "HTTPS" => "off", "HTTP_HOST" => "localhost", "REQUEST_URI" => "/path", "QUERY_STRING" => "" ] ], [ new Uri("https://foo.com/path/to/stuff?cat=molly"), [ "HTTPS" => "1", "HTTP_HOST" => "foo.com", "REQUEST_URI" => "/path/to/stuff?cat=molly", "QUERY_STRING" => "cat=molly" ] ], [ new Uri("http://foo.com:8080/path/to/stuff?cat=molly"), [ "HTTP" => "1", "HTTP_HOST" => "foo.com:8080", "REQUEST_URI" => "/path/to/stuff?cat=molly", "QUERY_STRING" => "cat=molly" ] ] ]; } // ------------------------------------------------------------------------ // Marshalling ServerRequest Information /** @depends testGetServerRequestReadsFromRequest */ public function testGetServerRequestReadsServerParams($request) { /** @var ServerRequest $request */ $this->assertEquals("localhost", $request->getServerParams()["HTTP_HOST"]); } /** @depends testGetServerRequestReadsFromRequest */ public function testGetServerRequestReadsCookieParams($request) { /** @var ServerRequest $request */ $this->assertEquals("Molly", $request->getCookieParams()["cat"]); } /** @depends testGetServerRequestReadsFromRequest */ public function testGetServerRequestReadsQueryParams($request) { /** @var ServerRequest $request */ $this->assertEquals("Claude", $request->getQueryParams()["guinea_pig"]); } /** * @backupGlobals enabled * @dataProvider uploadedFileProvider */ public function testGetServerRequestReadsUploadedFiles($file, $path) { $_SERVER = [ "HTTP_HOST" => "localhost", "HTTP_ACCEPT" => "application/json", "HTTP_CONTENT_TYPE" => "application/x-www-form-urlencoded" ]; $_FILES = [ "single" => [ "name" => "single.txt", "type" => "text/plain", "tmp_name" => "/tmp/php9hNlHe", "error" => UPLOAD_ERR_OK, "size" => 524 ], "nested" => [ "level2" => [ "name" => "nested.json", "type" => "application/json", "tmp_name" => "/tmp/phpadhjk", "error" => UPLOAD_ERR_OK, "size" => 1024 ] ], "nestedList" => [ "level2" => [ "name" => [ 0 => "nestedList0.jpg", 1 => "nestedList1.jpg", 2 => "" ], "type" => [ 0 => "image/jpeg", 1 => "image/jpeg", 2 => "" ], "tmp_name" => [ 0 => "/tmp/phpjpg0", 1 => "/tmp/phpjpg1", 2 => "" ], "error" => [ 0 => UPLOAD_ERR_OK, 1 => UPLOAD_ERR_OK, 2 => UPLOAD_ERR_NO_FILE ], "size" => [ 0 => 256, 1 => 4096, 2 => 0 ] ] ], "nestedDictionary" => [ "level2" => [ "name" => [ "file0" => "nestedDictionary0.jpg", "file1" => "nestedDictionary1.jpg" ], "type" => [ "file0" => "image/png", "file1" => "image/png" ], "tmp_name" => [ "file0" => "/tmp/phppng0", "file1" => "/tmp/phppng1" ], "error" => [ "file0" => UPLOAD_ERR_OK, "file1" => UPLOAD_ERR_OK ], "size" => [ "file0" => 256, "file1" => 4096 ] ] ] ]; $request = ServerRequest::getServerRequest(); $current = $request->getUploadedFiles(); foreach ($path as $item) { $current = $current[$item]; } $this->assertEquals($file, $current); } public function uploadedFileProvider() { return [ [new UploadedFile("single.txt", "text/plain", 524, "/tmp/php9hNlHe", UPLOAD_ERR_OK), ["single"]], [new UploadedFile("nested.json", "application/json", 1024, "/tmp/phpadhjk", UPLOAD_ERR_OK), ["nested", "level2"]], [new UploadedFile("nestedList0.jpg", "image/jpeg", 256, "/tmp/phpjpg0", UPLOAD_ERR_OK), ["nestedList", "level2", 0]], [new UploadedFile("nestedList1.jpg", "image/jpeg", 4096, "/tmp/phpjpg1", UPLOAD_ERR_OK), ["nestedList", "level2", 1]], [new UploadedFile("", "", 0, "", UPLOAD_ERR_NO_FILE), ["nestedList", "level2", 2]], [new UploadedFile("nestedDictionary0.jpg", "image/png", 256, "/tmp/phppng0", UPLOAD_ERR_OK), ["nestedDictionary", "level2", "file0"]], [new UploadedFile("nestedDictionary1.jpg", "image/png", 4096, "/tmp/phppngg1", UPLOAD_ERR_OK), ["nestedDictionary", "level2", "file1"]] ]; } /** * @backupGlobals enabled * @dataProvider formContentTypeProvider */ public function testGetServerRequestParsesFormBody($contentType) { $_SERVER = [ "HTTP_HOST" => "localhost", "HTTP_CONTENT_TYPE" => $contentType, ]; $_COOKIE = []; $_FILES = []; $_POST = [ "dog" => "Bear" ]; $request = ServerRequest::getServerRequest(); $this->assertEquals("Bear", $request->getParsedBody()["dog"]); } public function formContentTypeProvider() { return [ ["application/x-www-form-urlencoded"], ["multipart/form-data"] ]; } /** @depends testGetServerRequestReadsFromRequest */ public function testGetServerRequestProvidesAttributesIfPassed($request) { /** @var ServerRequest $request */ $this->assertEquals("Claude", $request->getAttribute("guinea_pig")); } // ------------------------------------------------------------------------ // Server Params public function testGetServerParamsReturnsEmptyArrayByDefault() { $request = new ServerRequest(); $this->assertEquals([], $request->getServerParams()); } // ------------------------------------------------------------------------ // Cookies public function testGetCookieParamsReturnsEmptyArrayByDefault() { $request = new ServerRequest(); $this->assertEquals([], $request->getCookieParams()); } /** @depends testGetServerRequestReadsFromRequest */ public function testWithCookieParamsCreatesNewInstance($request1) { /** @var ServerRequest $request1 */ $request2 = $request1->withCookieParams([ "cat" => "Oscar" ]); $this->assertNotEquals($request1->getCookieParams()["cat"], $request2->getCookieParams()["cat"]); } // ------------------------------------------------------------------------ // Query public function testGetQueryParamsReturnsEmptyArrayByDefault() { $request = new ServerRequest(); $this->assertEquals([], $request->getQueryParams()); } /** @depends testGetServerRequestReadsFromRequest */ public function testWithQueryParamsCreatesNewInstance($request1) { /** @var ServerRequest $request1 */ $request2 = $request1->withQueryParams([ "guinea_pig" => "Clyde" ]); $this->assertNotEquals($request1->getQueryParams()["guinea_pig"], $request2->getQueryParams()["guinea_pig"]); } // ------------------------------------------------------------------------ // Uploaded Files public function testGetUploadedFilesReturnsEmptyArrayByDefault() { $request = new ServerRequest(); $this->assertEquals([], $request->getUploadedFiles()); } /** @backupGlobals enabled */ public function testGetUploadedFilesReturnsEmptyArrayWhenNoFilesAreUploaded() { $_SERVER = [ "HTTP_HOST" => "localhost", "HTTP_ACCEPT" => "application/json", "HTTP_CONTENT_TYPE" => "application/x-www-form-urlencoded" ]; $_FILES = []; $request = ServerRequest::getServerRequest(); $this->assertSame([], $request->getUploadedFiles()); } public function testWithUploadedFilesCreatesNewInstance() { $uploadedFiles = [ "file" => new UploadedFile("index.html", "text/html", 524, "/tmp/php9hNlHe", 0) ]; $request = new ServerRequest(); $request1 = $request->withUploadedFiles([]); $request2 = $request1->withUploadedFiles($uploadedFiles); $this->assertNotSame($request2, $request1); } /** @dataProvider validUploadedFilesProvider */ public function testWithUploadedFilesStoresPassedUploadedFiles($uploadedFiles) { $request = new ServerRequest(); $request = $request->withUploadedFiles($uploadedFiles); $this->assertSame($uploadedFiles, $request->getUploadedFiles()); } public function validUploadedFilesProvider() { return [ [[]], [["files" => new UploadedFile("index.html", "text/html", 524, "/tmp/php9hNlHe", 0)]], [["nested" => [ "level2" => new UploadedFile("index.html", "text/html", 524, "/tmp/php9hNlHe", 0) ]]], [["nestedList" => [ "level2" => [ new UploadedFile("file1.html", "text/html", 524, "/tmp/php9hNlHe", 0), new UploadedFile("file2.html", "text/html", 524, "/tmp/php9hNshj", 0) ] ]]], [["nestedDictionary" => [ "level2" => [ "file1" => new UploadedFile("file1.html", "text/html", 524, "/tmp/php9hNlHe", 0), "file2" => new UploadedFile("file2.html", "text/html", 524, "/tmp/php9hNshj", 0) ] ]]] ]; } /** * @dataProvider invalidUploadedFilesProvider */ public function testWithUploadedFilesThrowsExceptionWithInvalidTree($uploadedFiles) { $this->expectException(InvalidArgumentException::class); $request = new ServerRequest(); $request->withUploadedFiles($uploadedFiles); } public function invalidUploadedFilesProvider() { return [ // All keys must be strings [[new UploadedFile("index.html", "text/html", 524, "/tmp/php9hNlHe", 0)]], [ [new UploadedFile("index1.html", "text/html", 524, "/tmp/php9hNlHe", 0)], [new UploadedFile("index2.html", "text/html", 524, "/tmp/php9hNlHe", 0)] ], [ "single" => [ "name" => "single.txt", "type" => "text/plain", "tmp_name" => "/tmp/php9hNlHe", "error" => UPLOAD_ERR_OK, "size" => 524 ], "nested" => [ "level2" => [ "name" => "nested.json", "type" => "application/json", "tmp_name" => "/tmp/phpadhjk", "error" => UPLOAD_ERR_OK, "size" => 1024 ] ] ], [ "nestedList" => [ "level2" => [ "name" => [ 0 => "nestedList0.jpg", 1 => "nestedList1.jpg", 2 => "" ], "type" => [ 0 => "image/jpeg", 1 => "image/jpeg", 2 => "" ], "tmp_name" => [ 0 => "/tmp/phpjpg0", 1 => "/tmp/phpjpg1", 2 => "" ], "error" => [ 0 => UPLOAD_ERR_OK, 1 => UPLOAD_ERR_OK, 2 => UPLOAD_ERR_NO_FILE ], "size" => [ 0 => 256, 1 => 4096, 2 => 0 ] ] ] ] ]; } // ------------------------------------------------------------------------ // Parsed Body public function testGetParsedBodyReturnsNullByDefault() { $request = new ServerRequest(); $this->assertNull($request->getParsedBody()); } /** @depends testGetServerRequestReadsFromRequest */ public function testWithParsedBodyCreatesNewInstance($request1) { /** @var ServerRequest $request1 */ $body1 = $request1->getParsedBody(); $request2 = $request1->withParsedBody([ "guinea_pig" => "Clyde" ]); $body2 = $request2->getParsedBody(); $this->assertNotSame($body1, $body2); } /** * @dataProvider invalidParsedBodyProvider */ public function testWithParsedBodyThrowsExceptionWithInvalidType($body) { $this->expectException(InvalidArgumentException::class); $request = new ServerRequest(); $request->withParsedBody($body); } public function invalidParsedBodyProvider() { return [ [false], [1] ]; } public function testCloneMakesDeepCopiesOfParsedBody() { $body = (object) [ "cat" => "Dog" ]; $request1 = new ServerRequest(); $request1 = $request1->withParsedBody($body); $request2 = $request1->withHeader("X-extra", "hello world"); $this->assertTrue( $request1->getParsedBody() == $request2->getParsedBody() && $request1->getParsedBody() !== $request2->getParsedBody() ); } // ------------------------------------------------------------------------ // Attributes public function testGetAttributesReturnsEmptyArrayByDefault() { $request = new ServerRequest(); $this->assertEquals([], $request->getAttributes()); } public function testGetAttributesReturnsAllAttributes() { $request = new ServerRequest(); $request = $request->withAttribute("cat", "Molly"); $request = $request->withAttribute("dog", "Bear"); $expected = [ "cat" => "Molly", "dog" => "Bear" ]; $this->assertEquals($expected, $request->getAttributes()); } public function testGetAttributeReturnsDefaultIfNotSet() { $request = new ServerRequest(); $this->assertEquals("Oscar", $request->getAttribute("cat", "Oscar")); } public function testWithAttributeCreatesNewInstance() { $request = new ServerRequest(); $request = $request->withAttribute("cat", "Molly"); $this->assertEquals("Molly", $request->getAttribute("cat")); } public function testWithAttributePreserversOtherAttributes() { $request = new ServerRequest(); $request = $request->withAttribute("cat", "Molly"); $request = $request->withAttribute("dog", "Bear"); $expected = [ "cat" => "Molly", "dog" => "Bear" ]; $this->assertEquals($expected, $request->getAttributes()); } public function testWithoutAttributeCreatesNewInstance() { $request = new ServerRequest(); $request = $request->withAttribute("cat", "Molly"); $this->assertNotEquals($request, $request->withoutAttribute("cat")); } public function testWithoutAttributeRemovesAttribute() { $request = new ServerRequest(); $request = $request->withAttribute("cat", "Molly"); $request = $request->withoutAttribute("cat"); $this->assertEquals("Oscar", $request->getAttribute("cat", "Oscar")); } public function testWithoutAttributePreservesOtherAttributes() { $request = new ServerRequest(); $request = $request->withAttribute("cat", "Molly"); $request = $request->withAttribute("dog", "Bear"); $request = $request->withoutAttribute("cat"); $this->assertEquals("Bear", $request->getAttribute("dog")); } }