Skip to content

Commit

Permalink
ImageServerPresenter tests
Browse files Browse the repository at this point in the history
- added tests for `ImageServerPresenter`
- added test methods in `ImageStorageExtensionTest`
- added `NoImageResolverTest`
- fixed PHPStan
  • Loading branch information
tg666 committed Jan 3, 2023
1 parent df8f2b9 commit 2012256
Show file tree
Hide file tree
Showing 15 changed files with 446 additions and 29 deletions.
1 change: 0 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
"phpstan/phpstan-nette": "^1.1",
"roave/security-advisories": "dev-latest",
"symfony/console": "^5.0 | ^6.0",
"tracy/tracy": "^2.6",
"yosymfony/toml": "^1.0.4"
},
"suggest": {
Expand Down
2 changes: 0 additions & 2 deletions phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,3 @@ parameters:
-
message: '#Parameter \$object of method SixtyEightPublishers\\ImageStorage\\Bridge\\Intervention\\Image\\Imagick\\Decoder::initFromImagick\(\) has invalid type Intervention\\Image\\Imagick\\Imagick.#'
path: src/Bridge/Intervention/Image/Imagick/Decoder.php
-
message: '#Return type \(Intervention\\Image\\Image\) of method [a-zA-Z\\]+::getSource\(\) should be compatible with return type \(resource\|string\) of method SixtyEightPublishers\\FileStorage\\Resource\\ResourceInterface::getSource\(\)#'
26 changes: 6 additions & 20 deletions src/Bridge/Nette/Application/ImageServerPresenter.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@

namespace SixtyEightPublishers\ImageStorage\Bridge\Nette\Application;

use Tracy\ILogger;
use Tracy\Debugger;
use Nette\Http\IRequest;
use Psr\Log\LoggerInterface;
use Nette\Application\IPresenter;
Expand All @@ -19,7 +17,6 @@
use function assert;
use function sprintf;
use function is_string;
use function class_exists;

class ImageServerPresenter implements IPresenter
{
Expand All @@ -46,25 +43,14 @@ public function run(ApplicationRequest $request): ApplicationResponse
$response = $storage->getImageResponse(new Request($this->request));
assert($response instanceof ApplicationResponse);

if ($response instanceof ErrorResponse) {
$this->logErrorResponse($response);
}

return $response;
}
if ($response instanceof ErrorResponse && null !== $this->logger) {
$exception = $response->getException();

private function logErrorResponse(ErrorResponse $response): void
{
if (null !== $this->logger) {
$this->logger->error($response->getException()->getMessage(), [
'exception' => $response->getException(),
$this->logger->error($exception->getMessage(), [
'exception' => $exception,
]);

return;
}

if (class_exists(Debugger::class)) {
Debugger::log($response->getException(), ILogger::ERROR);
}

return $response;
}
}
4 changes: 2 additions & 2 deletions src/Bridge/Nette/Application/ImageServerRoute.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@
namespace SixtyEightPublishers\ImageStorage\Bridge\Nette\Application;

use Nette\Application\Routers\Route;
use function rtrim;
use function trim;

final class ImageServerRoute extends Route
{
public function __construct(?string $storageName, string $basePath)
{
parent::__construct(rtrim($basePath) . '/<path .+>', [
parent::__construct('/' . trim($basePath, '/') . '/<path .+>', [
'module' => 'ImageStorage',
'presenter' => 'ImageServer',
'action' => 'default',
Expand Down
2 changes: 2 additions & 0 deletions src/Bridge/Nette/DI/ImageStorageExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -503,5 +503,7 @@ private function registerImageServerPresenter(): void
$this->getContainerBuilder()
->addDefinition($this->prefix('presenter.image_server'))
->setType(ImageServerPresenter::class);

$this->imageServerPresenterRegistered = true;
}
}
3 changes: 0 additions & 3 deletions src/NoImage/NoImageResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,6 @@ public function getNoImageConfig(): NoImageConfigInterface
return $this->noImageConfig;
}

/**
* @throws \SixtyEightPublishers\ImageStorage\Exception\InvalidStateException
*/
public function getNoImage(?string $name = null): PathInfoInterface
{
if (null === $name) {
Expand Down
2 changes: 2 additions & 0 deletions src/Persistence/ImagePersister.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
use SixtyEightPublishers\ImageStorage\Modifier\Facade\ModifierFacadeInterface;
use SixtyEightPublishers\FileStorage\PathInfoInterface as FilePathInfoInterface;
use SixtyEightPublishers\ImageStorage\PathInfoInterface as ImagePathInfoInterface;
use SixtyEightPublishers\ImageStorage\Resource\ResourceInterface as ImageResourceInterface;
use function assert;
use function sprintf;
use function is_scalar;
Expand Down Expand Up @@ -52,6 +53,7 @@ public function exists(FilePathInfoInterface $pathInfo): bool

public function save(ResourceInterface $resource, array $config = []): string
{
assert($resource instanceof ImageResourceInterface);
$pathInfo = $this->assertPathInfo($resource->getPathInfo(), __METHOD__);
$source = $resource->getSource();

Expand Down
3 changes: 3 additions & 0 deletions src/Resource/ImageResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ public function getPathInfo(): PathInfoInterface
return $this->pathInfo;
}

/**
* @phpstan-ignore-next-line
*/
public function getSource(): Image
{
return $this->image;
Expand Down
2 changes: 1 addition & 1 deletion src/Resource/ResourceInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
interface ResourceInterface extends FileResourceInterface
{
/**
* @return \Intervention\Image\Image
* @phpstan-ignore-next-line
*/
public function getSource(): Image;

Expand Down
178 changes: 178 additions & 0 deletions tests/Bridge/Nette/Application/ImageServerPresenterTest.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
<?php

declare(strict_types=1);

namespace SixtyEightPublishers\ImageStorage\Tests\Bridge\Nette\Application;

use Mockery;
use Tester\Assert;
use Tester\TestCase;
use Psr\Log\LogLevel;
use Nette\Http\UrlScript;
use Psr\Log\Test\TestLogger;
use Nette\Http\Request as NetteRequest;
use Nette\Application\Request as ApplicationRequest;
use SixtyEightPublishers\FileStorage\FileStorageInterface;
use SixtyEightPublishers\ImageStorage\ImageStorageInterface;
use SixtyEightPublishers\FileStorage\FileStorageProviderInterface;
use SixtyEightPublishers\ImageStorage\Exception\ResponseException;
use SixtyEightPublishers\ImageStorage\Exception\InvalidStateException;
use SixtyEightPublishers\ImageStorage\Bridge\Nette\ImageServer\ErrorResponse;
use SixtyEightPublishers\ImageStorage\Bridge\Nette\ImageServer\ImageResponse;
use SixtyEightPublishers\ImageStorage\Bridge\Nette\Application\ImageServerPresenter;
use SixtyEightPublishers\ImageStorage\Bridge\Nette\ImageServer\Request as ImageServerRequest;

require __DIR__ . '/../../../bootstrap.php';

final class ImageServerPresenterTest extends TestCase
{
public function testExceptionShouldBeThrownIfStorageIsNotInstanceOfImageStorageInterface(): void
{
$netteRequest = new NetteRequest(
new UrlScript('https://www.example.com/images/test/w:100/image.png?_v=123')
);
$fileStorageProvider = Mockery::mock(FileStorageProviderInterface::class);
$fileStorage = Mockery::mock(FileStorageInterface::class);

$fileStorage->shouldReceive('getName')
->once()
->withNoArgs()
->andReturn('default');

$fileStorageProvider->shouldReceive('get')
->once()
->with('default')
->andReturn($fileStorage);

$applicationRequest = new ApplicationRequest('ImageStorage:ImageServer:default', 'GET', [
'__storageName' => 'default',
]);

$presenter = new ImageServerPresenter($netteRequest, $fileStorageProvider);

Assert::exception(
static fn () => $presenter->run($applicationRequest),
InvalidStateException::class,
'File storage "default" must be implementor of an interface SixtyEightPublishers\ImageStorage\ImageStorageInterface.'
);
}

public function testImageResponseShouldBeReturned(): void
{
$netteRequest = new NetteRequest(
new UrlScript('https://www.example.com/images/test/w:100/image.png?_v=123')
);
$fileStorageProvider = Mockery::mock(FileStorageProviderInterface::class);
$imageStorage = Mockery::mock(ImageStorageInterface::class);
$imageResponse = Mockery::mock(ImageResponse::class);

$fileStorageProvider->shouldReceive('get')
->once()
->with('default')
->andReturn($imageStorage);

$imageStorage->shouldReceive('getImageResponse')
->once()
->with(Mockery::type(ImageServerRequest::class))
->andReturnUsing(static function (ImageServerRequest $request) use ($netteRequest, $imageResponse): ImageResponse {
Assert::same($netteRequest, $request->getOriginalRequest());

return $imageResponse;
});

$applicationRequest = new ApplicationRequest('ImageStorage:ImageServer:default', 'GET', [
'__storageName' => 'default',
]);

$presenter = new ImageServerPresenter($netteRequest, $fileStorageProvider);

Assert::same($imageResponse, $presenter->run($applicationRequest));
}

public function testErrorResponseShouldBeReturned(): void
{
$netteRequest = new NetteRequest(
new UrlScript('https://www.example.com/images/test/w:100/image.png?_v=123')
);
$fileStorageProvider = Mockery::mock(FileStorageProviderInterface::class);
$imageStorage = Mockery::mock(ImageStorageInterface::class);
$errorResponse = Mockery::mock(ErrorResponse::class);

$fileStorageProvider->shouldReceive('get')
->once()
->with('default')
->andReturn($imageStorage);

$imageStorage->shouldReceive('getImageResponse')
->once()
->with(Mockery::type(ImageServerRequest::class))
->andReturnUsing(static function (ImageServerRequest $request) use ($netteRequest, $errorResponse): ErrorResponse {
Assert::same($netteRequest, $request->getOriginalRequest());

return $errorResponse;
});

$applicationRequest = new ApplicationRequest('ImageStorage:ImageServer:default', 'GET', [
'__storageName' => 'default',
]);

$presenter = new ImageServerPresenter($netteRequest, $fileStorageProvider);

Assert::same($errorResponse, $presenter->run($applicationRequest));
}

public function testErrorResponseShouldBeReturnedAndLogged(): void
{
$netteRequest = new NetteRequest(
new UrlScript('https://www.example.com/images/test/w:100/image.png?_v=123')
);
$fileStorageProvider = Mockery::mock(FileStorageProviderInterface::class);
$imageStorage = Mockery::mock(ImageStorageInterface::class);
$errorResponse = Mockery::mock(ErrorResponse::class);
$exception = new ResponseException('File not found.', 404);
$logger = new TestLogger();

$fileStorageProvider->shouldReceive('get')
->once()
->with('default')
->andReturn($imageStorage);

$imageStorage->shouldReceive('getImageResponse')
->once()
->with(Mockery::type(ImageServerRequest::class))
->andReturnUsing(static function (ImageServerRequest $request) use ($netteRequest, $errorResponse): ErrorResponse {
Assert::same($netteRequest, $request->getOriginalRequest());

return $errorResponse;
});

$errorResponse->shouldReceive('getException')
->once()
->withNoArgs()
->andReturn($exception);

$applicationRequest = new ApplicationRequest('ImageStorage:ImageServer:default', 'GET', [
'__storageName' => 'default',
]);

$presenter = new ImageServerPresenter($netteRequest, $fileStorageProvider, $logger);

Assert::same($errorResponse, $presenter->run($applicationRequest));
Assert::same([
[
'level' => LogLevel::ERROR,
'message' => 'File not found.',
'context' => [
'exception' => $exception,
],
],
], $logger->records);
}

protected function tearDown(): void
{
Mockery::close();
}
}

(new ImageServerPresenterTest())->run();
Loading

0 comments on commit 2012256

Please sign in to comment.