Skip to content

Commit

Permalink
Move tests to each component
Browse files Browse the repository at this point in the history
  • Loading branch information
clue committed May 7, 2014
1 parent 7b9d293 commit c91fcd7
Show file tree
Hide file tree
Showing 4 changed files with 451 additions and 0 deletions.
137 changes: 137 additions & 0 deletions tests/RequestHeaderParserTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
<?php

namespace React\Tests\Http;

use React\Http\RequestHeaderParser;
use React\Tests\Socket\TestCase;

class RequestHeaderParserTest extends TestCase
{
public function testSplitShouldHappenOnDoubleCrlf()
{
$parser = new RequestHeaderParser();
$parser->on('headers', $this->expectCallableNever());

$parser->feed("GET / HTTP/1.1\r\n");
$parser->feed("Host: example.com:80\r\n");
$parser->feed("Connection: close\r\n");

$parser->removeAllListeners();
$parser->on('headers', $this->expectCallableOnce());

$parser->feed("\r\n");
}

public function testFeedInOneGo()
{
$parser = new RequestHeaderParser();
$parser->on('headers', $this->expectCallableOnce());

$data = $this->createGetRequest();
$parser->feed($data);
}

public function testHeadersEventShouldReturnRequestAndBodyBuffer()
{
$request = null;
$bodyBuffer = null;

$parser = new RequestHeaderParser();
$parser->on('headers', function ($parsedRequest, $parsedBodyBuffer) use (&$request, &$bodyBuffer) {
$request = $parsedRequest;
$bodyBuffer = $parsedBodyBuffer;
});

$data = $this->createGetRequest();
$data .= 'RANDOM DATA';
$parser->feed($data);

$this->assertInstanceOf('React\Http\Request', $request);
$this->assertSame('GET', $request->getMethod());
$this->assertSame('/', $request->getPath());
$this->assertSame(array(), $request->getQuery());
$this->assertSame('1.1', $request->getHttpVersion());
$this->assertSame(array('Host' => 'example.com:80', 'Connection' => 'close'), $request->getHeaders());

$this->assertSame('RANDOM DATA', $bodyBuffer);
}

public function testHeadersEventShouldReturnBinaryBodyBuffer()
{
$bodyBuffer = null;

$parser = new RequestHeaderParser();
$parser->on('headers', function ($parsedRequest, $parsedBodyBuffer) use (&$bodyBuffer) {
$bodyBuffer = $parsedBodyBuffer;
});

$data = $this->createGetRequest();
$data .= "\0x01\0x02\0x03\0x04\0x05";
$parser->feed($data);

$this->assertSame("\0x01\0x02\0x03\0x04\0x05", $bodyBuffer);
}

public function testHeadersEventShouldParsePathAndQueryString()
{
$request = null;

$parser = new RequestHeaderParser();
$parser->on('headers', function ($parsedRequest, $parsedBodyBuffer) use (&$request) {
$request = $parsedRequest;
});

$data = $this->createAdvancedPostRequest();
$parser->feed($data);

$this->assertInstanceOf('React\Http\Request', $request);
$this->assertSame('POST', $request->getMethod());
$this->assertSame('/foo', $request->getPath());
$this->assertSame(array('bar' => 'baz'), $request->getQuery());
$this->assertSame('1.1', $request->getHttpVersion());
$headers = array(
'Host' => 'example.com:80',
'User-Agent' => 'react/alpha',
'Connection' => 'close',
);
$this->assertSame($headers, $request->getHeaders());
}

public function testHeaderOverflowShouldEmitError()
{
$error = null;

$parser = new RequestHeaderParser();
$parser->on('headers', $this->expectCallableNever());
$parser->on('error', function ($message) use (&$error) {
$error = $message;
});

$data = str_repeat('A', 4097);
$parser->feed($data);

$this->assertInstanceOf('OverflowException', $error);
$this->assertSame('Maximum header size of 4096 exceeded.', $error->getMessage());
}

private function createGetRequest()
{
$data = "GET / HTTP/1.1\r\n";
$data .= "Host: example.com:80\r\n";
$data .= "Connection: close\r\n";
$data .= "\r\n";

return $data;
}

private function createAdvancedPostRequest()
{
$data = "POST /foo?bar=baz HTTP/1.1\r\n";
$data .= "Host: example.com:80\r\n";
$data .= "User-Agent: react/alpha\r\n";
$data .= "Connection: close\r\n";
$data .= "\r\n";

return $data;
}
}
27 changes: 27 additions & 0 deletions tests/RequestTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

namespace React\Tests\Http;

use React\Http\Request;
use React\Tests\Socket\TestCase;

class RequestTest extends TestCase
{
/** @test */
public function expectsContinueShouldBeFalseByDefault()
{
$headers = array();
$request = new Request('GET', '/', array(), '1.1', $headers);

$this->assertFalse($request->expectsContinue());
}

/** @test */
public function expectsContinueShouldBeTrueIfContinueExpected()
{
$headers = array('Expect' => '100-continue');
$request = new Request('GET', '/', array(), '1.1', $headers);

$this->assertTrue($request->expectsContinue());
}
}
206 changes: 206 additions & 0 deletions tests/ResponseTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
<?php

namespace React\Tests\Http;

use React\Http\Response;
use React\Tests\Socket\TestCase;

class ResponseTest extends TestCase
{
public function testResponseShouldBeChunkedByDefault()
{
$expected = '';
$expected .= "HTTP/1.1 200 OK\r\n";
$expected .= "X-Powered-By: React/alpha\r\n";
$expected .= "Transfer-Encoding: chunked\r\n";
$expected .= "\r\n";

$conn = $this->getMock('React\Socket\ConnectionInterface');
$conn
->expects($this->once())
->method('write')
->with($expected);

$response = new Response($conn);
$response->writeHead();
}

public function testResponseShouldNotBeChunkedWithContentLength()
{
$expected = '';
$expected .= "HTTP/1.1 200 OK\r\n";
$expected .= "X-Powered-By: React/alpha\r\n";
$expected .= "Content-Length: 22\r\n";
$expected .= "\r\n";

$conn = $this->getMock('React\Socket\ConnectionInterface');
$conn
->expects($this->once())
->method('write')
->with($expected);

$response = new Response($conn);
$response->writeHead(200, array('Content-Length' => 22));
}

public function testResponseBodyShouldBeChunkedCorrectly()
{
$conn = $this->getMock('React\Socket\ConnectionInterface');
$conn
->expects($this->at(4))
->method('write')
->with("5\r\nHello\r\n");
$conn
->expects($this->at(5))
->method('write')
->with("1\r\n \r\n");
$conn
->expects($this->at(6))
->method('write')
->with("6\r\nWorld\n\r\n");
$conn
->expects($this->at(7))
->method('write')
->with("0\r\n\r\n");

$response = new Response($conn);
$response->writeHead();

$response->write('Hello');
$response->write(' ');
$response->write("World\n");
$response->end();
}

public function testResponseShouldEmitEndOnStreamEnd()
{
$ended = false;

$conn = $this->getMock('React\Socket\ConnectionInterface');
$response = new Response($conn);

$response->on('end', function () use (&$ended) {
$ended = true;
});
$response->end();

$this->assertTrue($ended);
}

/** @test */
public function writeContinueShouldSendContinueLineBeforeRealHeaders()
{
$conn = $this->getMock('React\Socket\ConnectionInterface');
$conn
->expects($this->at(3))
->method('write')
->with("HTTP/1.1 100 Continue\r\n");
$conn
->expects($this->at(4))
->method('write')
->with($this->stringContains("HTTP/1.1 200 OK\r\n"));

$response = new Response($conn);
$response->writeContinue();
$response->writeHead();
}

/** @test */
public function shouldForwardEndDrainAndErrorEvents()
{
$conn = $this->getMock('React\Socket\ConnectionInterface');
$conn
->expects($this->at(0))
->method('on')
->with('end', $this->isInstanceOf('Closure'));
$conn
->expects($this->at(1))
->method('on')
->with('error', $this->isInstanceOf('Closure'));
$conn
->expects($this->at(2))
->method('on')
->with('drain', $this->isInstanceOf('Closure'));

$response = new Response($conn);
}

/** @test */
public function shouldRemoveNewlinesFromHeaders()
{
$expected = '';
$expected .= "HTTP/1.1 200 OK\r\n";
$expected .= "X-Powered-By: React/alpha\r\n";
$expected .= "FooBar: BazQux\r\n";
$expected .= "Transfer-Encoding: chunked\r\n";
$expected .= "\r\n";

$conn = $this->getMock('React\Socket\ConnectionInterface');
$conn
->expects($this->once())
->method('write')
->with($expected);

$response = new Response($conn);
$response->writeHead(200, array("Foo\nBar" => "Baz\rQux"));
}

/** @test */
public function missingStatusCodeTextShouldResultInNumberOnlyStatus()
{
$expected = '';
$expected .= "HTTP/1.1 700 \r\n";
$expected .= "X-Powered-By: React/alpha\r\n";
$expected .= "Transfer-Encoding: chunked\r\n";
$expected .= "\r\n";

$conn = $this->getMock('React\Socket\ConnectionInterface');
$conn
->expects($this->once())
->method('write')
->with($expected);

$response = new Response($conn);
$response->writeHead(700);
}

/** @test */
public function shouldAllowArrayHeaderValues()
{
$expected = '';
$expected .= "HTTP/1.1 200 OK\r\n";
$expected .= "X-Powered-By: React/alpha\r\n";
$expected .= "Set-Cookie: foo=bar\r\n";
$expected .= "Set-Cookie: bar=baz\r\n";
$expected .= "Transfer-Encoding: chunked\r\n";
$expected .= "\r\n";

$conn = $this->getMock('React\Socket\ConnectionInterface');
$conn
->expects($this->once())
->method('write')
->with($expected);

$response = new Response($conn);
$response->writeHead(200, array("Set-Cookie" => array("foo=bar", "bar=baz")));
}

/** @test */
public function shouldIgnoreHeadersWithNullValues()
{
$expected = '';
$expected .= "HTTP/1.1 200 OK\r\n";
$expected .= "X-Powered-By: React/alpha\r\n";
$expected .= "Transfer-Encoding: chunked\r\n";
$expected .= "\r\n";

$conn = $this->getMock('React\Socket\ConnectionInterface');
$conn
->expects($this->once())
->method('write')
->with($expected);

$response = new Response($conn);
$response->writeHead(200, array("FooBar" => null));
}
}
Loading

0 comments on commit c91fcd7

Please sign in to comment.