ldc-arcadia-genesis-php-client/tests/Unit/Service/ArcadiaIncoServiceTest.php

445 lines
15 KiB
PHP
Raw Permalink Normal View History

<?php
declare(strict_types=1);
namespace Tests\Unit\Service;
use Mockery;
use Uwil\ArcadiaApiPhpClient\Error\ApiError;
use Uwil\ArcadiaApiPhpClient\Error\ServerError;
use Uwil\ArcadiaApiPhpClient\Lib\ApiDto\Dto\Brand;
use Uwil\ArcadiaApiPhpClient\Lib\ApiDto\Dto\Inco;
use Uwil\ArcadiaApiPhpClient\Lib\ApiDto\Dto\Inco\Allegations;
use Uwil\ArcadiaApiPhpClient\Lib\ApiDto\Dto\Inco\Ingredients;
use Uwil\ArcadiaApiPhpClient\Lib\ApiDto\Dto\IncoCompo;
use Uwil\ArcadiaApiPhpClient\Lib\ApiDto\Dto\IncoShort;
use Uwil\ArcadiaApiPhpClient\Lib\ApiDto\Dto\PageOf;
use Uwil\ArcadiaApiPhpClient\Lib\ApiDto\Dto\PaginationDto;
use Uwil\ArcadiaApiPhpClient\Lib\ApiValueObject\BrandCode;
use Uwil\ArcadiaApiPhpClient\Lib\ApiValueObject\IncoCompoId;
use Uwil\ArcadiaApiPhpClient\Lib\ApiValueObject\IncoId;
use Uwil\ArcadiaApiPhpClient\Lib\Pagination\PageSize;
use Uwil\ArcadiaApiPhpClient\Lib\Pagination\Pagination;
use Uwil\ArcadiaApiPhpClient\Lib\Pagination\StreamOf;
use Uwil\ArcadiaApiPhpClient\Mapper\IncoCompoMapper;
use Uwil\ArcadiaApiPhpClient\Repository\IncoCompoRepository;
use Uwil\ArcadiaApiPhpClient\Repository\IncoRepository;
use Uwil\ArcadiaApiPhpClient\Repository\IncoShortRepository;
use Uwil\ArcadiaApiPhpClient\Service\ArcadiaIncoService;
use Uwil\ArcadiaKiotaOpenApiClient\Models\IncoCompo as KiotaIncoCompo;
/** @return array{
* \Uwil\ArcadiaApiPhpClient\Repository\IncoRepository&\Mockery\MockInterface,
* \Uwil\ArcadiaApiPhpClient\Repository\IncoShortRepository&\Mockery\MockInterface,
* \Uwil\ArcadiaApiPhpClient\Repository\IncoCompoRepository&\Mockery\MockInterface
* } */
function serviceIncoMocks(): array
{
return [
Mockery::mock(IncoRepository::class),
Mockery::mock(IncoShortRepository::class),
Mockery::mock(IncoCompoRepository::class),
];
}
function dummyIncoForService(): Inco
{
return new Inco(
id: new IncoId('12345'),
name: 'Poulet',
libelle: 'Poulet fermier',
description: 'Description',
allegations: new Allegations([], [], [], []),
sellArguments: '',
preparationAdvices: '',
tips: null,
sellFamilly: null,
ingredients: new Ingredients([]),
portions: null,
allergens: [],
brand: new Brand(code: new BrandCode('LGL39'), label: 'Le Gaulois'),
isSeasonal: false,
weight: null,
nutriscore: null,
storageCondition: null,
additives: [],
compo: null,
createdAt: null,
updatedAt: null,
);
}
function dummyIncoShortForService(): IncoShort
{
return new IncoShort(
id: new IncoId('12345'),
name: 'Poulet',
libelle: 'Poulet fermier',
description: 'Description',
created_at: null,
updated_at: null,
);
}
function dummyIncoCompoForService(): IncoCompo
{
return (new IncoCompoMapper())->toDto(new KiotaIncoCompo());
}
describe('ArcadiaIncoService', function () {
describe('getAll', function () {
it('returns PageOf when repository succeeds', function () {
// GIVEN
$pagination = Pagination::firstPage();
$expectedPage = new PageOf(
new PaginationDto(page: 1, pageSize: 50, totalItems: 1, totalPages: 1),
[dummyIncoShortForService()]
);
[$incoRepo, $shortRepo, $compoRepo] = serviceIncoMocks();
$shortRepo->shouldReceive('selectAll')
->once()
->with($pagination, null)
->andReturn($expectedPage);
$service = new ArcadiaIncoService($incoRepo, $shortRepo, $compoRepo);
// WHEN
$result = $service->getAll($pagination);
// THEN
expect($result)->toBe($expectedPage);
});
it('returns ApiError when repository fails', function () {
// GIVEN
$pagination = Pagination::firstPage();
$error = new ServerError('Internal Server Error', 500);
[$incoRepo, $shortRepo, $compoRepo] = serviceIncoMocks();
$shortRepo->shouldReceive('selectAll')
->once()
->with($pagination, null)
->andReturn($error);
$service = new ArcadiaIncoService($incoRepo, $shortRepo, $compoRepo);
// WHEN
$result = $service->getAll($pagination);
// THEN
expect($result)->toBeInstanceOf(ApiError::class);
expect($result)->toBe($error);
});
});
describe('getAllOfBrands', function () {
it('returns PageOf when given a single BrandCode', function () {
// GIVEN
$pagination = Pagination::firstPage();
$brand = new BrandCode('LGL39');
$expectedPage = new PageOf(
new PaginationDto(page: 1, pageSize: 50, totalItems: 1, totalPages: 1),
[dummyIncoShortForService()]
);
[$incoRepo, $shortRepo, $compoRepo] = serviceIncoMocks();
$shortRepo->shouldReceive('selectAllHavingBrands')
->once()
->with($pagination, [$brand], null)
->andReturn($expectedPage);
$service = new ArcadiaIncoService($incoRepo, $shortRepo, $compoRepo);
// WHEN
$result = $service->getAllOfBrands($pagination, $brand);
// THEN
expect($result)->toBe($expectedPage);
});
it('throws InvalidArgumentException when brands is empty', function () {
// GIVEN
$pagination = Pagination::firstPage();
[$incoRepo, $shortRepo, $compoRepo] = serviceIncoMocks();
$service = new ArcadiaIncoService($incoRepo, $shortRepo, $compoRepo);
// WHEN / THEN
expect(fn () => $service->getAllOfBrands($pagination, []))
->toThrow(\InvalidArgumentException::class, 'At least 1 brand code is required');
});
it('throws InvalidArgumentException when element is not BrandCode', function () {
// GIVEN
$pagination = Pagination::firstPage();
[$incoRepo, $shortRepo, $compoRepo] = serviceIncoMocks();
$service = new ArcadiaIncoService($incoRepo, $shortRepo, $compoRepo);
// WHEN / THEN
expect(fn () => $service->getAllOfBrands($pagination, ['not-a-brand'])) // @phpstan-ignore-line
->toThrow(\InvalidArgumentException::class, 'Expected instance of ' . BrandCode::class);
});
});
describe('getAllOfBrandsSince', function () {
it('returns PageOf when given valid brands and since', function () {
// GIVEN
$pagination = Pagination::firstPage();
$brand = new BrandCode('LGL39');
$since = new \DateTimeImmutable('2024-01-01');
$expectedPage = new PageOf(
new PaginationDto(page: 1, pageSize: 50, totalItems: 1, totalPages: 1),
[dummyIncoShortForService()]
);
[$incoRepo, $shortRepo, $compoRepo] = serviceIncoMocks();
$shortRepo->shouldReceive('selectAllHavingBrandsSince')
->once()
->with($pagination, $since, [$brand], \SortDirection::Descending)
->andReturn($expectedPage);
$service = new ArcadiaIncoService($incoRepo, $shortRepo, $compoRepo);
// WHEN
$result = $service->getAllOfBrandsSince($pagination, $brand, $since);
// THEN
expect($result)->toBe($expectedPage);
});
});
describe('findByIncoIdLike', function () {
it('returns PageOf when search succeeds', function () {
// GIVEN
$brand = new BrandCode('LGL39');
$expectedPage = new PageOf(
new PaginationDto(page: 1, pageSize: 50, totalItems: 1, totalPages: 1),
[dummyIncoShortForService()]
);
[$incoRepo, $shortRepo, $compoRepo] = serviceIncoMocks();
$shortRepo->shouldReceive('findWhere')
->once()
->andReturn($expectedPage);
$service = new ArcadiaIncoService($incoRepo, $shortRepo, $compoRepo);
// WHEN
$result = $service->findByIncoIdLike('poulet', $brand);
// THEN
expect($result)->toBe($expectedPage);
});
it('throws InvalidArgumentException when no brands are passed', function () {
// GIVEN
[$incoRepo, $shortRepo, $compoRepo] = serviceIncoMocks();
$service = new ArcadiaIncoService($incoRepo, $shortRepo, $compoRepo);
// WHEN / THEN
expect(fn () => $service->findByIncoIdLike('poulet'))
->toThrow(\InvalidArgumentException::class, 'At least 1 brand code is required');
});
});
describe('findBy', function () {
it('returns Inco when found', function () {
// GIVEN
$id = new IncoId('12345');
$expectedInco = dummyIncoForService();
[$incoRepo, $shortRepo, $compoRepo] = serviceIncoMocks();
$incoRepo->shouldReceive('find')
->once()
->with($id)
->andReturn($expectedInco);
$service = new ArcadiaIncoService($incoRepo, $shortRepo, $compoRepo);
// WHEN
$result = $service->findBy($id);
// THEN
expect($result)->toBe($expectedInco);
});
it('returns null when not found', function () {
// GIVEN
$id = new IncoId('12345');
[$incoRepo, $shortRepo, $compoRepo] = serviceIncoMocks();
$incoRepo->shouldReceive('find')
->once()
->with($id)
->andReturnNull();
$service = new ArcadiaIncoService($incoRepo, $shortRepo, $compoRepo);
// WHEN
$result = $service->findBy($id);
// THEN
expect($result)->toBeNull();
});
it('returns ApiError when repository fails', function () {
// GIVEN
$id = new IncoId('12345');
$error = new ServerError('Internal Server Error', 500);
[$incoRepo, $shortRepo, $compoRepo] = serviceIncoMocks();
$incoRepo->shouldReceive('find')
->once()
->with($id)
->andReturn($error);
$service = new ArcadiaIncoService($incoRepo, $shortRepo, $compoRepo);
// WHEN
$result = $service->findBy($id);
// THEN
expect($result)->toBeInstanceOf(ApiError::class);
expect($result)->toBe($error);
});
});
describe('findCompo', function () {
it('delegates to find when given IncoCompoId', function () {
// GIVEN
$id = new IncoCompoId('99');
$expectedCompo = dummyIncoCompoForService();
[$incoRepo, $shortRepo, $compoRepo] = serviceIncoMocks();
$compoRepo->shouldReceive('find')
->once()
->with($id)
->andReturn($expectedCompo);
$service = new ArcadiaIncoService($incoRepo, $shortRepo, $compoRepo);
// WHEN
$result = $service->findCompo($id);
// THEN
expect($result)->toBe($expectedCompo);
});
it('delegates to findFor when given IncoId', function () {
// GIVEN
$id = new IncoId('12345');
$expectedCompo = dummyIncoCompoForService();
[$incoRepo, $shortRepo, $compoRepo] = serviceIncoMocks();
$compoRepo->shouldReceive('findFor')
->once()
->with($id)
->andReturn($expectedCompo);
$service = new ArcadiaIncoService($incoRepo, $shortRepo, $compoRepo);
// WHEN
$result = $service->findCompo($id);
// THEN
expect($result)->toBe($expectedCompo);
});
it('returns null when composition not found', function () {
// GIVEN
$id = new IncoId('12345');
[$incoRepo, $shortRepo, $compoRepo] = serviceIncoMocks();
$compoRepo->shouldReceive('findFor')
->once()
->with($id)
->andReturnNull();
$service = new ArcadiaIncoService($incoRepo, $shortRepo, $compoRepo);
// WHEN
$result = $service->findCompo($id);
// THEN
expect($result)->toBeNull();
});
});
describe('streaming methods', function () {
it('streamAll returns StreamOf yielding inco shorts', function () {
// GIVEN
$incoShort = dummyIncoShortForService();
$expectedPage = new PageOf(
new PaginationDto(page: 1, pageSize: 50, totalItems: 1, totalPages: 1),
[$incoShort]
);
[$incoRepo, $shortRepo, $compoRepo] = serviceIncoMocks();
$shortRepo->shouldReceive('selectAll')
->once()
->andReturn($expectedPage);
$service = new ArcadiaIncoService($incoRepo, $shortRepo, $compoRepo);
// WHEN
$stream = $service->streamAll(new PageSize(50));
$items = iterator_to_array($stream);
// THEN
expect($stream)->toBeInstanceOf(StreamOf::class);
expect($items)->toHaveCount(1);
expect($items[0])->toBe($incoShort);
});
it('streamAllOfBrands returns StreamOf yielding inco shorts', function () {
// GIVEN
$incoShort = dummyIncoShortForService();
$expectedPage = new PageOf(
new PaginationDto(page: 1, pageSize: 50, totalItems: 1, totalPages: 1),
[$incoShort]
);
[$incoRepo, $shortRepo, $compoRepo] = serviceIncoMocks();
$shortRepo->shouldReceive('selectAllHavingBrands')
->once()
->andReturn($expectedPage);
$service = new ArcadiaIncoService($incoRepo, $shortRepo, $compoRepo);
// WHEN
$stream = $service->streamAllOfBrands(new BrandCode('LGL39'));
$items = iterator_to_array($stream);
// THEN
expect($stream)->toBeInstanceOf(StreamOf::class);
expect($items)->toHaveCount(1);
expect($items[0])->toBe($incoShort);
});
it('streamAllOfBrandsSince returns StreamOf yielding inco shorts', function () {
// GIVEN
$incoShort = dummyIncoShortForService();
$expectedPage = new PageOf(
new PaginationDto(page: 1, pageSize: 50, totalItems: 1, totalPages: 1),
[$incoShort]
);
[$incoRepo, $shortRepo, $compoRepo] = serviceIncoMocks();
$shortRepo->shouldReceive('selectAllHavingBrandsSince')
->once()
->andReturn($expectedPage);
$service = new ArcadiaIncoService($incoRepo, $shortRepo, $compoRepo);
// WHEN
$stream = $service->streamAllOfBrandsSince(new BrandCode('LGL39'), new \DateTimeImmutable('2024-01-01'));
$items = iterator_to_array($stream);
// THEN
expect($stream)->toBeInstanceOf(StreamOf::class);
expect($items)->toHaveCount(1);
expect($items[0])->toBe($incoShort);
});
});
});