[#ED-1] Ajout des API de lecture bovin (#2)
| Numéro du ticket | Titre du ticket | |------------------|-----------------| | | | ## Description de la PR ## Modification du .env ## Check list - [ ] Pas de régression - [x] TU/TI/TF rédigée - [x] TU/TI/TF OK - [ ] CHANGELOG modifié Reviewed-on: #2 Co-authored-by: tristan <tristan@yuno.malio.fr> Co-committed-by: tristan <tristan@yuno.malio.fr>
This commit was merged in pull request #2.
This commit is contained in:
0
tests/Unit/.gitkeep
Normal file
0
tests/Unit/.gitkeep
Normal file
70
tests/Unit/Bovin/Mapper/AnimalSummaryMapperTest.php
Normal file
70
tests/Unit/Bovin/Mapper/AnimalSummaryMapperTest.php
Normal file
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Malio\EdnotifBundle\Tests\Unit\Bovin\Mapper;
|
||||
|
||||
use Malio\EdnotifBundle\Bovin\Dto\AnimalSummaryDto;
|
||||
use Malio\EdnotifBundle\Bovin\Mapper\AnimalSummaryMapper;
|
||||
use PHPUnit\Framework\Attributes\CoversClass;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
#[CoversClass(AnimalSummaryMapper::class)]
|
||||
final class AnimalSummaryMapperTest extends TestCase
|
||||
{
|
||||
public function testMapReturnsIdentificationAndPresencePeriods(): void
|
||||
{
|
||||
$node = $this->makeBovinNode();
|
||||
|
||||
$summary = new AnimalSummaryMapper()->map($node);
|
||||
|
||||
self::assertInstanceOf(AnimalSummaryDto::class, $summary);
|
||||
self::assertNotNull($summary->identification);
|
||||
self::assertSame('FR1234567890', $summary->identification->bovin?->nationalNumber);
|
||||
self::assertSame('F', $summary->identification->sex);
|
||||
self::assertCount(2, $summary->presencePeriods);
|
||||
}
|
||||
|
||||
public function testMapHandlesMissingOptionalNodes(): void
|
||||
{
|
||||
$summary = new AnimalSummaryMapper()->map(new stdClass());
|
||||
|
||||
self::assertNull($summary->identification);
|
||||
self::assertSame([], $summary->presencePeriods);
|
||||
}
|
||||
|
||||
private function makeBovinNode(): object
|
||||
{
|
||||
$node = new stdClass();
|
||||
$node->IdentiteBovin = new stdClass();
|
||||
$node->IdentiteBovin->Sexe = 'F';
|
||||
$node->IdentiteBovin->Bovin = new stdClass();
|
||||
$node->IdentiteBovin->Bovin->CodePays = 'FR';
|
||||
$node->IdentiteBovin->Bovin->NumeroNational = 'FR1234567890';
|
||||
|
||||
$node->PeriodesPresences = new stdClass();
|
||||
$node->PeriodesPresences->PeriodePresence = [
|
||||
$this->makePresencePeriod('2024-01-10', '2024-06-01'),
|
||||
$this->makePresencePeriod('2024-06-02', null),
|
||||
];
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
private function makePresencePeriod(string $entryDate, ?string $exitDate): object
|
||||
{
|
||||
$period = new stdClass();
|
||||
$period->Entree = new stdClass();
|
||||
$period->Entree->DateEntree = $entryDate;
|
||||
if (null !== $exitDate) {
|
||||
$period->Sortie = new stdClass();
|
||||
$period->Sortie->DateSortie = $exitDate;
|
||||
}
|
||||
|
||||
return $period;
|
||||
}
|
||||
}
|
||||
100
tests/Unit/Bovin/Mapper/InventoryMapperTest.php
Normal file
100
tests/Unit/Bovin/Mapper/InventoryMapperTest.php
Normal file
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Malio\EdnotifBundle\Tests\Unit\Bovin\Mapper;
|
||||
|
||||
use DateTimeImmutable;
|
||||
use Malio\EdnotifBundle\Bovin\Dto\InventoryDto;
|
||||
use Malio\EdnotifBundle\Bovin\Mapper\AnimalSummaryMapper;
|
||||
use Malio\EdnotifBundle\Bovin\Mapper\InventoryMapper;
|
||||
use Malio\EdnotifBundle\Shared\Mapper\StandardResponseMapper;
|
||||
use PHPUnit\Framework\Attributes\CoversClass;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
#[CoversClass(InventoryMapper::class)]
|
||||
final class InventoryMapperTest extends TestCase
|
||||
{
|
||||
public function testMapFullInventory(): void
|
||||
{
|
||||
$mapper = new InventoryMapper(new AnimalSummaryMapper(), new StandardResponseMapper());
|
||||
|
||||
$inventory = $mapper->map($this->makeSoapResponse(), $this->makeUnzippedMessage());
|
||||
|
||||
self::assertInstanceOf(InventoryDto::class, $inventory);
|
||||
self::assertTrue($inventory->standardResponse->result);
|
||||
self::assertSame(2, $inventory->nbBovins);
|
||||
self::assertEquals(new DateTimeImmutable('2026-01-01'), $inventory->startDate);
|
||||
self::assertEquals(new DateTimeImmutable('2026-01-31'), $inventory->endDate);
|
||||
self::assertTrue($inventory->includesEarTagStock);
|
||||
self::assertCount(2, $inventory->animals);
|
||||
self::assertCount(1, $inventory->earTagSeries);
|
||||
self::assertSame('FR123', $inventory->animals[0]->identification?->bovin?->nationalNumber);
|
||||
}
|
||||
|
||||
public function testMapInventoryWithoutMessageZipReturnsEmptyLists(): void
|
||||
{
|
||||
$mapper = new InventoryMapper(new AnimalSummaryMapper(), new StandardResponseMapper());
|
||||
|
||||
$soapResponse = new stdClass();
|
||||
$soapResponse->ReponseStandard = new stdClass();
|
||||
$soapResponse->ReponseStandard->Resultat = true;
|
||||
$soapResponse->ReponseSpecifique = new stdClass();
|
||||
$soapResponse->ReponseSpecifique->NbBovins = 0;
|
||||
|
||||
$inventory = $mapper->map($soapResponse, null);
|
||||
|
||||
self::assertSame(0, $inventory->nbBovins);
|
||||
self::assertSame([], $inventory->animals);
|
||||
self::assertSame([], $inventory->earTagSeries);
|
||||
self::assertNull($inventory->startDate);
|
||||
}
|
||||
|
||||
private function makeSoapResponse(): object
|
||||
{
|
||||
$response = new stdClass();
|
||||
$response->ReponseStandard = new stdClass();
|
||||
$response->ReponseStandard->Resultat = true;
|
||||
$response->ReponseSpecifique = new stdClass();
|
||||
$response->ReponseSpecifique->NbBovins = 2;
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
private function makeUnzippedMessage(): object
|
||||
{
|
||||
$message = new stdClass();
|
||||
$message->InformationsMessage = new stdClass();
|
||||
$message->InformationsMessage->DateDebut = '2026-01-01';
|
||||
$message->InformationsMessage->DateFin = '2026-01-31';
|
||||
$message->InformationsMessage->StockBoucles = '1';
|
||||
$message->Bovins = new stdClass();
|
||||
$message->Bovins->Bovin = [
|
||||
$this->makeAnimalNode('FR123'),
|
||||
$this->makeAnimalNode('FR456'),
|
||||
];
|
||||
$message->Boucles = new stdClass();
|
||||
$message->Boucles->SerieBoucles = new stdClass();
|
||||
$message->Boucles->SerieBoucles->NumeroSerieDebut = 'A0001';
|
||||
|
||||
return $message;
|
||||
}
|
||||
|
||||
private function makeAnimalNode(string $nationalNumber): object
|
||||
{
|
||||
$node = new stdClass();
|
||||
$node->IdentiteBovin = new stdClass();
|
||||
$node->IdentiteBovin->Bovin = new stdClass();
|
||||
$node->IdentiteBovin->Bovin->NumeroNational = $nationalNumber;
|
||||
$node->PeriodesPresences = new stdClass();
|
||||
$node->PeriodesPresences->PeriodePresence = new stdClass();
|
||||
$node->PeriodesPresences->PeriodePresence->Entree = new stdClass();
|
||||
$node->PeriodesPresences->PeriodePresence->Entree->DateEntree = '2025-05-01';
|
||||
|
||||
return $node;
|
||||
}
|
||||
}
|
||||
72
tests/Unit/Bovin/Mapper/PresumedExitsMapperTest.php
Normal file
72
tests/Unit/Bovin/Mapper/PresumedExitsMapperTest.php
Normal file
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Malio\EdnotifBundle\Tests\Unit\Bovin\Mapper;
|
||||
|
||||
use DateTimeImmutable;
|
||||
use Malio\EdnotifBundle\Bovin\Dto\PresumedExitsDto;
|
||||
use Malio\EdnotifBundle\Bovin\Mapper\PresumedExitsMapper;
|
||||
use Malio\EdnotifBundle\Shared\Mapper\StandardResponseMapper;
|
||||
use PHPUnit\Framework\Attributes\CoversClass;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
#[CoversClass(PresumedExitsMapper::class)]
|
||||
final class PresumedExitsMapperTest extends TestCase
|
||||
{
|
||||
public function testMapWithExits(): void
|
||||
{
|
||||
$soapResponse = new stdClass();
|
||||
$soapResponse->ReponseStandard = new stdClass();
|
||||
$soapResponse->ReponseStandard->Resultat = true;
|
||||
$soapResponse->ReponseSpecifique = new stdClass();
|
||||
$soapResponse->ReponseSpecifique->NbBovins = 2;
|
||||
|
||||
$message = new stdClass();
|
||||
$message->SortiesPresumees = new stdClass();
|
||||
$message->SortiesPresumees->SortiePresumee = [
|
||||
$this->makeExit('FR111', '2026-02-15'),
|
||||
$this->makeExit('FR222', null),
|
||||
];
|
||||
|
||||
$dto = new PresumedExitsMapper(new StandardResponseMapper())->map($soapResponse, $message);
|
||||
|
||||
self::assertInstanceOf(PresumedExitsDto::class, $dto);
|
||||
self::assertSame(2, $dto->nbBovins);
|
||||
self::assertCount(2, $dto->presumedExits);
|
||||
self::assertSame('FR111', $dto->presumedExits[0]->bovin?->nationalNumber);
|
||||
self::assertEquals(new DateTimeImmutable('2026-02-15'), $dto->presumedExits[0]->exitDate);
|
||||
self::assertNull($dto->presumedExits[1]->exitDate);
|
||||
}
|
||||
|
||||
public function testMapWithoutMessageReturnsEmpty(): void
|
||||
{
|
||||
$soapResponse = new stdClass();
|
||||
$soapResponse->ReponseStandard = new stdClass();
|
||||
$soapResponse->ReponseStandard->Resultat = true;
|
||||
$soapResponse->ReponseSpecifique = new stdClass();
|
||||
$soapResponse->ReponseSpecifique->NbBovins = 0;
|
||||
|
||||
$dto = new PresumedExitsMapper(new StandardResponseMapper())->map($soapResponse, null);
|
||||
|
||||
self::assertSame(0, $dto->nbBovins);
|
||||
self::assertSame([], $dto->presumedExits);
|
||||
}
|
||||
|
||||
private function makeExit(string $nationalNumber, ?string $exitDate): object
|
||||
{
|
||||
$node = new stdClass();
|
||||
$node->Bovin = new stdClass();
|
||||
$node->Bovin->CodePays = 'FR';
|
||||
$node->Bovin->NumeroNational = $nationalNumber;
|
||||
if (null !== $exitDate) {
|
||||
$node->DateSortie = $exitDate;
|
||||
}
|
||||
|
||||
return $node;
|
||||
}
|
||||
}
|
||||
67
tests/Unit/Bovin/Mapper/ReturnedDossiersMapperTest.php
Normal file
67
tests/Unit/Bovin/Mapper/ReturnedDossiersMapperTest.php
Normal file
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Malio\EdnotifBundle\Tests\Unit\Bovin\Mapper;
|
||||
|
||||
use DateTimeImmutable;
|
||||
use Malio\EdnotifBundle\Bovin\Dto\ReturnedDossiersDto;
|
||||
use Malio\EdnotifBundle\Bovin\Mapper\AnimalSummaryMapper;
|
||||
use Malio\EdnotifBundle\Bovin\Mapper\ReturnedDossiersMapper;
|
||||
use Malio\EdnotifBundle\Shared\Mapper\StandardResponseMapper;
|
||||
use PHPUnit\Framework\Attributes\CoversClass;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
#[CoversClass(ReturnedDossiersMapper::class)]
|
||||
final class ReturnedDossiersMapperTest extends TestCase
|
||||
{
|
||||
public function testMapReturnsAnimalsAndStartDate(): void
|
||||
{
|
||||
$mapper = new ReturnedDossiersMapper(new AnimalSummaryMapper(), new StandardResponseMapper());
|
||||
|
||||
$soapResponse = new stdClass();
|
||||
$soapResponse->ReponseStandard = new stdClass();
|
||||
$soapResponse->ReponseStandard->Resultat = true;
|
||||
$soapResponse->ReponseSpecifique = new stdClass();
|
||||
$soapResponse->ReponseSpecifique->NbBovins = 1;
|
||||
|
||||
$message = new stdClass();
|
||||
$message->InformationsMessage = new stdClass();
|
||||
$message->InformationsMessage->DateDebut = '2026-03-01';
|
||||
$message->Bovins = new stdClass();
|
||||
$message->Bovins->Bovin = new stdClass();
|
||||
$message->Bovins->Bovin->IdentiteBovin = new stdClass();
|
||||
$message->Bovins->Bovin->IdentiteBovin->Bovin = new stdClass();
|
||||
$message->Bovins->Bovin->IdentiteBovin->Bovin->NumeroNational = 'FR789';
|
||||
$message->Bovins->Bovin->PeriodesPresences = new stdClass();
|
||||
$message->Bovins->Bovin->PeriodesPresences->PeriodePresence = new stdClass();
|
||||
|
||||
$dto = $mapper->map($soapResponse, $message);
|
||||
|
||||
self::assertInstanceOf(ReturnedDossiersDto::class, $dto);
|
||||
self::assertEquals(new DateTimeImmutable('2026-03-01'), $dto->startDate);
|
||||
self::assertSame(1, $dto->nbBovins);
|
||||
self::assertCount(1, $dto->animals);
|
||||
self::assertSame('FR789', $dto->animals[0]->identification?->bovin?->nationalNumber);
|
||||
}
|
||||
|
||||
public function testMapWithoutMessageReturnsEmptyAnimals(): void
|
||||
{
|
||||
$mapper = new ReturnedDossiersMapper(new AnimalSummaryMapper(), new StandardResponseMapper());
|
||||
|
||||
$soapResponse = new stdClass();
|
||||
$soapResponse->ReponseStandard = new stdClass();
|
||||
$soapResponse->ReponseStandard->Resultat = true;
|
||||
$soapResponse->ReponseSpecifique = new stdClass();
|
||||
$soapResponse->ReponseSpecifique->NbBovins = 0;
|
||||
|
||||
$dto = $mapper->map($soapResponse, null);
|
||||
|
||||
self::assertSame(0, $dto->nbBovins);
|
||||
self::assertSame([], $dto->animals);
|
||||
}
|
||||
}
|
||||
79
tests/Unit/Shared/Soap/ZipMessageDecoderTest.php
Normal file
79
tests/Unit/Shared/Soap/ZipMessageDecoderTest.php
Normal file
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Malio\EdnotifBundle\Tests\Unit\Shared\Soap;
|
||||
|
||||
use Malio\EdnotifBundle\Shared\Soap\ZipMessageDecoder;
|
||||
use PHPUnit\Framework\Attributes\CoversClass;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use RuntimeException;
|
||||
use ZipArchive;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
#[CoversClass(ZipMessageDecoder::class)]
|
||||
final class ZipMessageDecoderTest extends TestCase
|
||||
{
|
||||
public function testDecodeReturnsObjectFromZippedXml(): void
|
||||
{
|
||||
$xml = '<?xml version="1.0" encoding="UTF-8"?>'
|
||||
.'<MessageIpBNotifGetInventaire>'
|
||||
.'<InformationsMessage><DateDebut>2026-01-01</DateDebut></InformationsMessage>'
|
||||
.'<Bovins><Bovin><IdentiteBovin><Sexe>F</Sexe></IdentiteBovin></Bovin></Bovins>'
|
||||
.'</MessageIpBNotifGetInventaire>';
|
||||
|
||||
$zipBinary = $this->makeZipBinary('message.xml', $xml);
|
||||
$decoded = new ZipMessageDecoder()->decode($zipBinary);
|
||||
|
||||
self::assertIsObject($decoded);
|
||||
self::assertSame('2026-01-01', (string) $decoded->InformationsMessage->DateDebut);
|
||||
self::assertSame('F', (string) $decoded->Bovins->Bovin->IdentiteBovin->Sexe);
|
||||
}
|
||||
|
||||
public function testDecodeProducesArrayForMultiChildNodes(): void
|
||||
{
|
||||
$xml = '<?xml version="1.0" encoding="UTF-8"?>'
|
||||
.'<MessageIpBNotifGetInventaire>'
|
||||
.'<Bovins>'
|
||||
.'<Bovin><IdentiteBovin><Sexe>F</Sexe></IdentiteBovin></Bovin>'
|
||||
.'<Bovin><IdentiteBovin><Sexe>M</Sexe></IdentiteBovin></Bovin>'
|
||||
.'</Bovins>'
|
||||
.'</MessageIpBNotifGetInventaire>';
|
||||
|
||||
$decoded = new ZipMessageDecoder()->decode($this->makeZipBinary('message.xml', $xml));
|
||||
|
||||
self::assertIsArray($decoded->Bovins->Bovin);
|
||||
self::assertCount(2, $decoded->Bovins->Bovin);
|
||||
self::assertSame('F', (string) $decoded->Bovins->Bovin[0]->IdentiteBovin->Sexe);
|
||||
self::assertSame('M', (string) $decoded->Bovins->Bovin[1]->IdentiteBovin->Sexe);
|
||||
}
|
||||
|
||||
public function testDecodeThrowsOnEmptyBinary(): void
|
||||
{
|
||||
$this->expectException(RuntimeException::class);
|
||||
new ZipMessageDecoder()->decode('');
|
||||
}
|
||||
|
||||
public function testDecodeThrowsOnInvalidZip(): void
|
||||
{
|
||||
$this->expectException(RuntimeException::class);
|
||||
new ZipMessageDecoder()->decode('not a zip');
|
||||
}
|
||||
|
||||
private function makeZipBinary(string $innerFile, string $content): string
|
||||
{
|
||||
$tempFile = tempnam(sys_get_temp_dir(), 'test_zip_');
|
||||
self::assertIsString($tempFile);
|
||||
$zip = new ZipArchive();
|
||||
self::assertTrue(true === $zip->open($tempFile, ZipArchive::CREATE | ZipArchive::OVERWRITE));
|
||||
self::assertTrue($zip->addFromString($innerFile, $content));
|
||||
self::assertTrue($zip->close());
|
||||
$binary = file_get_contents($tempFile);
|
||||
@unlink($tempFile);
|
||||
self::assertIsString($binary);
|
||||
|
||||
return $binary;
|
||||
}
|
||||
}
|
||||
5
tests/bootstrap.php
Normal file
5
tests/bootstrap.php
Normal file
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
require __DIR__.'/../vendor/autoload.php';
|
||||
Reference in New Issue
Block a user