Skip to content

Commit

Permalink
Dispatcher tests
Browse files Browse the repository at this point in the history
  • Loading branch information
mabar committed Aug 21, 2018
1 parent 14dc6d9 commit eb7a78e
Show file tree
Hide file tree
Showing 12 changed files with 444 additions and 0 deletions.
51 changes: 51 additions & 0 deletions tests/cases/Dispatcher/CoreDispatcher.phpt
@@ -0,0 +1,51 @@
<?php declare(strict_types = 1);

/**
* Test: Dispatcher\CoreDispatcher
*/

require_once __DIR__ . '/../../bootstrap.php';

use Apitte\Core\Dispatcher\CoreDispatcher;
use Apitte\Core\Exception\Logical\BadRequestException;
use Apitte\Core\Exception\Logical\InvalidStateException;
use Contributte\Psr7\Psr7ResponseFactory;
use Contributte\Psr7\Psr7ServerRequestFactory;
use Psr\Http\Message\ResponseInterface;
use Tester\Assert;
use Tests\Fixtures\Handler\FakeNullHandler;
use Tests\Fixtures\Handler\FakeResponseHandler;
use Tests\Fixtures\Router\FakeRouter;

// Request matched, use handler, return response
test(function (): void {
$request = Psr7ServerRequestFactory::fromSuperGlobal();
$response = Psr7ResponseFactory::fromGlobal();

$dispatcher = new CoreDispatcher(new FakeRouter(true), new FakeResponseHandler());
Assert::same($response, $dispatcher->dispatch($request, $response));
});

// Request matched, use invalid handler, throw exception
test(function (): void {
$request = Psr7ServerRequestFactory::fromSuperGlobal();
$response = Psr7ResponseFactory::fromGlobal();

$dispatcher = new CoreDispatcher(new FakeRouter(true), new FakeNullHandler());

Assert::exception(function () use ($dispatcher, $request, $response): void {
$dispatcher->dispatch($request, $response);
}, InvalidStateException::class, sprintf('Handler returned response must implement "%s"', ResponseInterface::class));
});

// Request not matched, throw exception
test(function (): void {
$request = Psr7ServerRequestFactory::fromSuperGlobal();
$response = Psr7ResponseFactory::fromGlobal();

$dispatcher = new CoreDispatcher(new FakeRouter(false), new FakeResponseHandler());

Assert::exception(function () use ($dispatcher, $request, $response): void {
$dispatcher->dispatch($request, $response);
}, BadRequestException::class, 'No matched route by given URL');
});
144 changes: 144 additions & 0 deletions tests/cases/Dispatcher/DecoratedDispatcher.phpt
@@ -0,0 +1,144 @@
<?php declare(strict_types = 1);

/**
* Test: Dispatcher\DecoratedDispatcher
*/

require_once __DIR__ . '/../../bootstrap.php';

use Apitte\Core\Decorator\DecoratorManager;
use Apitte\Core\Decorator\IDecorator;
use Apitte\Core\Dispatcher\DecoratedDispatcher;
use Apitte\Core\Exception\Logical\BadRequestException;
use Apitte\Core\Exception\Logical\InvalidStateException;
use Apitte\Core\Http\ApiResponse;
use Apitte\Core\Http\RequestAttributes;
use Apitte\Core\Schema\Endpoint;
use Contributte\Psr7\Psr7ResponseFactory;
use Contributte\Psr7\Psr7ServerRequestFactory;
use Psr\Http\Message\ResponseInterface;
use Tester\Assert;
use Tests\Fixtures\Decorator\EarlyReturnResponseExceptionDecorator;
use Tests\Fixtures\Decorator\ReturnNullDecorator;
use Tests\Fixtures\Decorator\ThrowExceptionFromContextResponseDecorator;
use Tests\Fixtures\Handler\ErroneousHandler;
use Tests\Fixtures\Handler\FakeNullHandler;
use Tests\Fixtures\Handler\FakeResponseHandler;
use Tests\Fixtures\Router\FakeRouter;

//TODO - EarlyReturnResponseException
// - decorateRequest
// - decorateResponse

// Match request, use handler and be happy, everything is ok!
test(function (): void {
$request = Psr7ServerRequestFactory::fromSuperGlobal();
$response = Psr7ResponseFactory::fromGlobal();

$dispatcher = new DecoratedDispatcher(new FakeRouter(true), new FakeResponseHandler(), new DecoratorManager());
Assert::same($response, $dispatcher->dispatch($request, $response));
});

// Match request, add endpoint, use handler and be happy, everything is ok!
test(function (): void {
$request = Psr7ServerRequestFactory::fromSuperGlobal();
$response = new ApiResponse(Psr7ResponseFactory::fromGlobal());

$endpoint = new Endpoint();
$request = $request->withAttribute(RequestAttributes::ATTR_ENDPOINT, $endpoint);

$dispatcher = new DecoratedDispatcher(new FakeRouter(true), new FakeResponseHandler(), new DecoratorManager());
$response = $dispatcher->dispatch($request, $response);
Assert::same($response->getAttribute(RequestAttributes::ATTR_ENDPOINT), $endpoint);
});

// Match request, use invalid handler, throw exception
test(function (): void {
$request = Psr7ServerRequestFactory::fromSuperGlobal();
$response = Psr7ResponseFactory::fromGlobal();

$dispatcher = new DecoratedDispatcher(new FakeRouter(true), new FakeNullHandler(), new DecoratorManager());

Assert::exception(function () use ($dispatcher, $request, $response): void {
$dispatcher->dispatch($request, $response);
}, InvalidStateException::class, sprintf('Handler returned response must implement "%s"', ResponseInterface::class));
});

// Match request, decorate request, throw exception, return response from exception
test(function (): void {
$request = Psr7ServerRequestFactory::fromSuperGlobal();
$response = Psr7ResponseFactory::fromGlobal();

$manager = new DecoratorManager();
$manager->addDecorator(IDecorator::ON_HANDLER_BEFORE, new EarlyReturnResponseExceptionDecorator());

$dispatcher = new DecoratedDispatcher(new FakeRouter(true), new FakeResponseHandler(), $manager);

Assert::same($response, $dispatcher->dispatch($request, $response));
});

// Match request, use handler, decorate response, throw exception, return response from exception
test(function (): void {
$request = Psr7ServerRequestFactory::fromSuperGlobal();
$response = Psr7ResponseFactory::fromGlobal();

$manager = new DecoratorManager();
$manager->addDecorator(IDecorator::ON_HANDLER_AFTER, new EarlyReturnResponseExceptionDecorator());

$dispatcher = new DecoratedDispatcher(new FakeRouter(true), new FakeResponseHandler(), $manager);

Assert::same($response, $dispatcher->dispatch($request, $response));
});

// Match request, use handler, throw and catch exception, decorate response with exception in context and then (for tests) throw exception again
test(function (): void {
$request = Psr7ServerRequestFactory::fromSuperGlobal();
$response = Psr7ResponseFactory::fromGlobal();

$manager = new DecoratorManager();
$manager->addDecorator(IDecorator::ON_DISPATCHER_EXCEPTION, new ThrowExceptionFromContextResponseDecorator());

$dispatcher = new DecoratedDispatcher(new FakeRouter(true), new ErroneousHandler(), $manager);

Assert::exception(function () use ($dispatcher, $request, $response): void {
$response = $dispatcher->dispatch($request, $response);
}, RuntimeException::class, sprintf('I am %s!', ErroneousHandler::class));
});

// Match request, use handler, throw and catch exception then trow it again because DecoratorManager doesn't have any decorators so returned null
test(function (): void {
$request = Psr7ServerRequestFactory::fromSuperGlobal();
$response = Psr7ResponseFactory::fromGlobal();

$dispatcher = new DecoratedDispatcher(new FakeRouter(true), new ErroneousHandler(), new DecoratorManager());
Assert::exception(function () use ($dispatcher, $request, $response): void {
$response = $dispatcher->dispatch($request, $response);
}, RuntimeException::class, sprintf('I am %s!', ErroneousHandler::class));
});

// Match request, use handler, throw and catch exception then throw it again because decorator returned null response
test(function (): void {
$request = Psr7ServerRequestFactory::fromSuperGlobal();
$response = Psr7ResponseFactory::fromGlobal();

$manager = new DecoratorManager();
$manager->addDecorator(IDecorator::ON_DISPATCHER_EXCEPTION, new ReturnNullDecorator());

$dispatcher = new DecoratedDispatcher(new FakeRouter(true), new ErroneousHandler(), $manager);

Assert::exception(function () use ($dispatcher, $request, $response): void {
$response = $dispatcher->dispatch($request, $response);
}, RuntimeException::class, sprintf('I am %s!', ErroneousHandler::class));
});

// No match, throw exception
test(function (): void {
$request = Psr7ServerRequestFactory::fromSuperGlobal();
$response = Psr7ResponseFactory::fromGlobal();

$dispatcher = new DecoratedDispatcher(new FakeRouter(false), new FakeResponseHandler(), new DecoratorManager());

Assert::exception(function () use ($dispatcher, $request, $response): void {
$response = $dispatcher->dispatch($request, $response);
}, BadRequestException::class, 'No matched route by given URL');
});
64 changes: 64 additions & 0 deletions tests/cases/Dispatcher/JsonDispatcher.phpt
@@ -0,0 +1,64 @@
<?php declare(strict_types = 1);

/**
* Test: Dispatcher\JsonDispatcher
*/

require_once __DIR__ . '/../../bootstrap.php';

use Apitte\Core\Dispatcher\JsonDispatcher;
use Apitte\Core\Exception\Logical\InvalidStateException;
use Contributte\Psr7\Psr7ResponseFactory;
use Contributte\Psr7\Psr7ServerRequestFactory;
use Nette\Utils\Json;
use Psr\Http\Message\ResponseInterface;
use Tester\Assert;
use Tests\Fixtures\Handler\FakeNullHandler;
use Tests\Fixtures\Handler\FakeResponseHandler;
use Tests\Fixtures\Handler\ReturnFooBarHandler;
use Tests\Fixtures\Router\FakeRouter;

// Matched, use handle
test(function (): void {
$request = Psr7ServerRequestFactory::fromSuperGlobal();
$response = Psr7ResponseFactory::fromGlobal();

$dispatcher = new JsonDispatcher(new FakeRouter(true), new FakeResponseHandler());
Assert::same($response, $dispatcher->dispatch($request, $response));
});

// Matched, use handle, write to response body result from handle
test(function (): void {
$request = Psr7ServerRequestFactory::fromSuperGlobal();
$response = Psr7ResponseFactory::fromGlobal();

$dispatcher = new JsonDispatcher(new FakeRouter(true), new ReturnFooBarHandler());
$response = $dispatcher->dispatch($request, $response);

Assert::same(200, $response->getStatusCode());
Assert::same(Json::encode(['foo', 'bar']), (string) $response->getBody());
});

// Matched, use invalid handle, throw exception
test(function (): void {
$request = Psr7ServerRequestFactory::fromSuperGlobal();
$response = Psr7ResponseFactory::fromGlobal();

$dispatcher = new JsonDispatcher(new FakeRouter(true), new FakeNullHandler());
Assert::exception(function () use ($dispatcher, $request, $response): void {
$dispatcher->dispatch($request, $response);
}, InvalidStateException::class, sprintf('Handler returned response must implement "%s"', ResponseInterface::class));
});

// Not matched, use fallback, write error to response body
test(function (): void {
$request = Psr7ServerRequestFactory::fromSuperGlobal();
$response = Psr7ResponseFactory::fromGlobal();

$dispatcher = new JsonDispatcher(new FakeRouter(false), new FakeResponseHandler());
$response = $dispatcher->dispatch($request, $response);

Assert::same(404, $response->getStatusCode());
Assert::same(['application/json'], $response->getHeader('Content-Type'));
Assert::same(Json::encode(['error' => 'No matched route by given URL']), (string) $response->getBody());
});
22 changes: 22 additions & 0 deletions tests/cases/Dispatcher/WrappedDispatcher.phpt
@@ -0,0 +1,22 @@
<?php declare(strict_types = 1);

/**
* Test: Dispatcher\WrappedDispatcher
*/

require_once __DIR__ . '/../../bootstrap.php';

use Apitte\Core\Dispatcher\WrappedDispatcher;
use Contributte\Psr7\Psr7ResponseFactory;
use Contributte\Psr7\Psr7ServerRequestFactory;
use Tester\Assert;
use Tests\Fixtures\Dispatcher\FakeDispatcher;

test(function (): void {
$request = Psr7ServerRequestFactory::fromSuperGlobal();
$response = Psr7ResponseFactory::fromGlobal();

$dispatcher = new WrappedDispatcher(new FakeDispatcher());

Assert::same($response, $dispatcher->dispatch($request, $response));
});
21 changes: 21 additions & 0 deletions tests/fixtures/Decorator/EarlyReturnResponseExceptionDecorator.php
@@ -0,0 +1,21 @@
<?php declare(strict_types = 1);

namespace Tests\Fixtures\Decorator;

use Apitte\Core\Decorator\IDecorator;
use Apitte\Core\Exception\Runtime\EarlyReturnResponseException;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;

class EarlyReturnResponseExceptionDecorator implements IDecorator
{

/**
* @param mixed[] $context
*/
public function decorate(ServerRequestInterface $request, ResponseInterface $response, array $context = []): void
{
throw new EarlyReturnResponseException($response);
}

}
@@ -0,0 +1,23 @@
<?php declare(strict_types = 1);

namespace Tests\Fixtures\Decorator;

use Apitte\Core\Decorator\IDecorator;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;

class ThrowExceptionFromContextResponseDecorator implements IDecorator
{

/**
* @param mixed[] $context
*/
public function decorate(ServerRequestInterface $request, ResponseInterface $response, array $context = []): ResponseInterface
{
if (isset($context['exception'])) {
throw $context['exception'];
}
return $response;
}

}
17 changes: 17 additions & 0 deletions tests/fixtures/Dispatcher/FakeDispatcher.php
@@ -0,0 +1,17 @@
<?php declare(strict_types = 1);

namespace Tests\Fixtures\Dispatcher;

use Apitte\Core\Dispatcher\IDispatcher;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;

class FakeDispatcher implements IDispatcher
{

public function dispatch(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
return $response;
}

}
18 changes: 18 additions & 0 deletions tests/fixtures/Handler/ErroneousHandler.php
@@ -0,0 +1,18 @@
<?php declare(strict_types = 1);

namespace Tests\Fixtures\Handler;

use Apitte\Core\Handler\IHandler;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use RuntimeException;

class ErroneousHandler implements IHandler
{

public function handle(ServerRequestInterface $request, ResponseInterface $response): void
{
throw new RuntimeException(sprintf('I am %s!', self::class));
}

}
20 changes: 20 additions & 0 deletions tests/fixtures/Handler/FakeNullHandler.php
@@ -0,0 +1,20 @@
<?php declare(strict_types = 1);

namespace Tests\Fixtures\Handler;

use Apitte\Core\Handler\IHandler;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;

class FakeNullHandler implements IHandler
{

/**
* @return null
*/
public function handle(ServerRequestInterface $request, ResponseInterface $response)
{
return null;
}

}

0 comments on commit eb7a78e

Please sign in to comment.