BaseExporterTest.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422
  1. <?php
  2. namespace App\Tests\Unit\Service\Export;
  3. use App\ApiResources\Export\ExportRequest;
  4. use App\Entity\Access\Access;
  5. use App\Entity\Core\File;
  6. use App\Entity\Organization\Organization;
  7. use App\Enum\Core\FileFolderEnum;
  8. use App\Enum\Core\FileTypeEnum;
  9. use App\Enum\Core\FileVisibilityEnum;
  10. use App\Enum\Export\ExportFormatEnum;
  11. use App\Repository\Access\AccessRepository;
  12. use App\Repository\Core\FileRepository;
  13. use App\Service\Export\BaseExporter;
  14. use App\Service\Export\Encoder\EncoderInterface;
  15. use App\Service\Export\Model\ExportModelInterface;
  16. use App\Service\File\FileManager;
  17. use App\Service\ServiceIterator\EncoderIterator;
  18. use App\Service\Utils\FileUtils;
  19. use Doctrine\ORM\EntityManagerInterface;
  20. use PHPUnit\Framework\MockObject\MockObject;
  21. use PHPUnit\Framework\TestCase;
  22. use Psr\Log\LoggerInterface;
  23. use Twig\Environment;
  24. use Twig\Error\SyntaxError;
  25. class TestableBaseExporter extends BaseExporter
  26. {
  27. public function buildModel(ExportRequest $exportRequest): ExportModelInterface
  28. {
  29. return parent::buildModel($exportRequest);
  30. }
  31. public function getBasename(): string
  32. {
  33. return parent::getBasename();
  34. }
  35. public function getTemplatePath(): string
  36. {
  37. return parent::getTemplatePath();
  38. }
  39. public function render(ExportModelInterface $model): string
  40. {
  41. return parent::render($model);
  42. }
  43. public function encode(string $html, string $format): string
  44. {
  45. return parent::encode($html, $format);
  46. }
  47. public function getFileBasename(ExportRequest $exportRequest): string
  48. {
  49. return parent::getFileBasename($exportRequest);
  50. }
  51. public function getFileType(): FileTypeEnum
  52. {
  53. return parent::getFileType();
  54. }
  55. }
  56. class BaseExporterTest extends TestCase
  57. {
  58. private MockObject|AccessRepository $accessRepository;
  59. private MockObject|FileRepository $fileRepository;
  60. private MockObject|Environment $twig;
  61. private MockObject|EncoderIterator $encoderIterator;
  62. private MockObject|EntityManagerInterface $entityManager;
  63. private MockObject|LoggerInterface $logger;
  64. private MockObject|FileManager $fileManager;
  65. private MockObject|FileUtils $fileUtils;
  66. public function setUp(): void
  67. {
  68. $this->accessRepository = $this->getMockBuilder(AccessRepository::class)->disableOriginalConstructor()->getMock();
  69. $this->fileRepository = $this->getMockBuilder(FileRepository::class)->disableOriginalConstructor()->getMock();
  70. $this->twig = $this->getMockBuilder(Environment::class)->disableOriginalConstructor()->getMock();
  71. $this->encoderIterator = $this->getMockBuilder(EncoderIterator::class)->disableOriginalConstructor()->getMock();
  72. $this->entityManager = $this->getMockBuilder(EntityManagerInterface::class)->disableOriginalConstructor()->getMock();
  73. $this->logger = $this->getMockBuilder(LoggerInterface::class)->disableOriginalConstructor()->getMock();
  74. $this->fileManager = $this->getMockBuilder(FileManager::class)->disableOriginalConstructor()->getMock();
  75. $this->fileUtils = $this->getMockBuilder(FileUtils::class)->disableOriginalConstructor()->getMock();
  76. }
  77. private function getBaseExporterMockFor(string $method): MockObject|TestableBaseExporter
  78. {
  79. $exporter = $this->getMockBuilder(TestableBaseExporter::class)
  80. ->setMethodsExcept([$method, 'setAccessRepository', 'setFileRepository', 'setTwig', 'setEncoderIterator',
  81. 'setEntityManager', 'setFileManager', 'setLogger', 'setFileUtils'])
  82. ->getMock();
  83. $exporter->setAccessRepository($this->accessRepository);
  84. $exporter->setFileRepository($this->fileRepository);
  85. $exporter->setTwig($this->twig);
  86. $exporter->setEncoderIterator($this->encoderIterator);
  87. $exporter->setEntityManager($this->entityManager);
  88. $exporter->setLogger($this->logger);
  89. $exporter->setFileManager($this->fileManager);
  90. $exporter->setFileUtils($this->fileUtils);
  91. return $exporter;
  92. }
  93. /**
  94. * @see BaseExporter::support()
  95. */
  96. public function testSupport(): void
  97. {
  98. $exporter = $this->getBaseExporterMockFor('support');
  99. $exportRequest = $this->getMockBuilder(ExportRequest::class)->disableOriginalConstructor()->getMock();
  100. $this->assertFalse($exporter->support($exportRequest));
  101. }
  102. /**
  103. * @see BaseExporter::export()
  104. */
  105. public function testExport(): void
  106. {
  107. $exporter = $this->getBaseExporterMockFor('export');
  108. $exportRequest = $this->getMockBuilder(ExportRequest::class)->disableOriginalConstructor()->getMock();
  109. $exportRequest->method('getRequesterId')->willReturn(123);
  110. $exportRequest->method('getFileId')->willReturn(456);
  111. $exportRequest->method('getFormat')->willReturn(ExportFormatEnum::PDF);
  112. $model = $this->getMockBuilder(ExportModelInterface::class)->disableOriginalConstructor()->getMock();
  113. $exporter->expects(self::once())->method('buildModel')->with($exportRequest)->willReturn($model);
  114. $html = '<div>foo</div>';
  115. $exporter->expects(self::once())->method('render')->with($model)->willReturn($html);
  116. $data = 'azerty';
  117. $exporter->expects(self::once())->method('encode')->with($html)->willReturn($data);
  118. $access = $this->getMockBuilder(Access::class)->disableOriginalConstructor()->getMock();
  119. $this->accessRepository->method('find')->with(123, null, null)->willReturn($access);
  120. $file = $this->getMockBuilder(File::class)->disableOriginalConstructor()->getMock();
  121. $this->fileRepository->method('find')->with(456, null, null)->willReturn($file);
  122. $this->fileManager->expects(self::once())->method('write')->with($file, $data, $access);
  123. $exporter->export($exportRequest);
  124. }
  125. /**
  126. * @see BaseExporter::export()
  127. */
  128. public function testExportNewFile(): void
  129. {
  130. $exporter = $this->getBaseExporterMockFor('export');
  131. $exportRequest = $this->getMockBuilder(ExportRequest::class)->disableOriginalConstructor()->getMock();
  132. $exportRequest->method('getRequesterId')->willReturn(123);
  133. $exportRequest->method('getFileId')->willReturn(null);
  134. $exportRequest->method('getFormat')->willReturn(ExportFormatEnum::PDF);
  135. $model = $this->getMockBuilder(ExportModelInterface::class)->disableOriginalConstructor()->getMock();
  136. $exporter->expects(self::once())->method('buildModel')->with($exportRequest)->willReturn($model);
  137. $html = '<div>foo</div>';
  138. $exporter->expects(self::once())->method('render')->with($model)->willReturn($html);
  139. $data = 'azerty';
  140. $exporter->expects(self::once())->method('encode')->with($html)->willReturn($data);
  141. $organization = $this->getMockBuilder(Organization::class)->disableOriginalConstructor()->getMock();
  142. $access = $this->getMockBuilder(Access::class)->disableOriginalConstructor()->getMock();
  143. $access->method('getOrganization')->willReturn($organization);
  144. $this->accessRepository->method('find')->with(123, null, null)->willReturn($access);
  145. $file = $this->getMockBuilder(File::class)->disableOriginalConstructor()->getMock();
  146. $exporter->expects(self::once())->method('prepareFile')->willReturn($file);
  147. $this->fileManager->expects(self::once())->method('write')->with($file, $data, $access);
  148. $exporter->export($exportRequest);
  149. }
  150. /**
  151. * @see BaseExporter::export()
  152. */
  153. public function testExportUndefinedRequester(): void
  154. {
  155. $exporter = $this->getBaseExporterMockFor('export');
  156. $exportRequest = $this->getMockBuilder(ExportRequest::class)->disableOriginalConstructor()->getMock();
  157. $exportRequest->method('getRequesterId')->willReturn(123);
  158. $exportRequest->method('getFileId')->willReturn(456);
  159. $exportRequest->method('getFormat')->willReturn(ExportFormatEnum::PDF);
  160. $this->accessRepository->method('find')->with(123, null, null)->willReturn(null);
  161. $this->fileManager->expects(self::never())->method('write');
  162. $this->expectException(\RuntimeException::class);
  163. $this->expectExceptionMessage('Unable to determine the user; abort.');
  164. $exporter->export($exportRequest);
  165. }
  166. /**
  167. * @see BaseExporter::export()
  168. */
  169. public function testExportUndefinedOrganization(): void
  170. {
  171. $exporter = $this->getBaseExporterMockFor('export');
  172. $exportRequest = $this->getMockBuilder(ExportRequest::class)->disableOriginalConstructor()->getMock();
  173. $exportRequest->method('getRequesterId')->willReturn(123);
  174. $exportRequest->method('getFileId')->willReturn(null);
  175. $exportRequest->method('getFormat')->willReturn(ExportFormatEnum::PDF);
  176. $model = $this->getMockBuilder(ExportModelInterface::class)->disableOriginalConstructor()->getMock();
  177. $exporter->expects(self::once())->method('buildModel')->with($exportRequest)->willReturn($model);
  178. $html = '<div>foo</div>';
  179. $exporter->expects(self::once())->method('render')->with($model)->willReturn($html);
  180. $data = 'azerty';
  181. $exporter->expects(self::once())->method('encode')->with($html)->willReturn($data);
  182. $access = $this->getMockBuilder(Access::class)->disableOriginalConstructor()->getMock();
  183. $access->method('getOrganization')->willReturn(null);
  184. $this->accessRepository->method('find')->with(123, null, null)->willReturn($access);
  185. $this->fileManager->expects(self::never())->method('write');
  186. $this->expectException(\RuntimeException::class);
  187. $this->expectExceptionMessage('Unable to determine the organization of the curent user; abort.');
  188. $exporter->export($exportRequest);
  189. }
  190. /**
  191. * @see BaseExporter::prepareFile()
  192. */
  193. public function testPrepareFile(): void
  194. {
  195. $exporter = $this->getBaseExporterMockFor('prepareFile');
  196. $exportRequest = $this->getMockBuilder(ExportRequest::class)->disableOriginalConstructor()->getMock();
  197. $exportRequest->method('getRequesterId')->willReturn(123);
  198. $exportRequest->method('getFormat')->willReturn(ExportFormatEnum::PDF);
  199. $access = $this->getMockBuilder(Access::class)->disableOriginalConstructor()->getMock();
  200. $this->accessRepository->method('find')->with(123, null, null)->willReturn($access);
  201. $exporter->method('getFileBasename')->with($exportRequest)->willReturn('Foo');
  202. $exporter->method('getFileType')->willReturn(FileTypeEnum::UNKNOWN);
  203. $file = $this->getMockBuilder(File::class)->disableOriginalConstructor()->getMock();
  204. $this->fileUtils->method('getMimeTypeFromExt')->with('pdf')->willReturn('application/pdf');
  205. $this->fileManager->expects(self::once())
  206. ->method('prepareFile')
  207. ->with(
  208. $access,
  209. 'Foo.pdf',
  210. FileTypeEnum::UNKNOWN,
  211. $access,
  212. true,
  213. FileVisibilityEnum::NOBODY,
  214. 'application/pdf',
  215. false,
  216. FileFolderEnum::DOCUMENTS
  217. )->willReturn($file);
  218. $result = $exporter->prepareFile($exportRequest, false);
  219. $this->assertSame($file, $result);
  220. }
  221. /**
  222. * @see BaseExporter::prepareFile()
  223. */
  224. public function testPrepareFileUndefinedRequester(): void
  225. {
  226. $exporter = $this->getBaseExporterMockFor('prepareFile');
  227. $exportRequest = $this->getMockBuilder(ExportRequest::class)->disableOriginalConstructor()->getMock();
  228. $exportRequest->method('getRequesterId')->willReturn(123);
  229. $this->accessRepository->method('find')->with(123, null, null)->willReturn(null);
  230. $this->expectException(\RuntimeException::class);
  231. $this->expectExceptionMessage('Unable to determine the current user; abort.');
  232. $exporter->prepareFile($exportRequest, false);
  233. }
  234. /**
  235. * @see BaseExporter::buildModel()
  236. */
  237. public function testBuildModel(): void
  238. {
  239. $exporter = $this->getBaseExporterMockFor('buildModel');
  240. $exportRequest = $this->getMockBuilder(ExportRequest::class)->disableOriginalConstructor()->getMock();
  241. $this->expectException(\RuntimeException::class);
  242. $this->expectExceptionMessage('not implemented error');
  243. $exporter->buildModel($exportRequest);
  244. }
  245. /**
  246. * @see BaseExporter::getBasename()
  247. */
  248. public function testGetBaseName(): void
  249. {
  250. $exporter = new TestableBaseExporter();
  251. $this->assertEquals('testable_base', $exporter->getBasename());
  252. }
  253. /**
  254. * @see BaseExporter::getTemplatePath()
  255. */
  256. public function testGetTemplatePath(): void
  257. {
  258. $exporter = $this->getBaseExporterMockFor('getTemplatePath');
  259. $exporter->method('getBaseName')->willReturn('base_exporter');
  260. $this->assertEquals('@templates/export/base_exporter.html.twig', $exporter->getTemplatePath());
  261. }
  262. /**
  263. * @see BaseExporter::render()
  264. */
  265. public function testRender(): void
  266. {
  267. $exporter = $this->getBaseExporterMockFor('render');
  268. $exporter->method('getTemplatePath')->willReturn('/path/to/template.html.twig');
  269. $model = $this->getMockBuilder(ExportModelInterface::class)->disableOriginalConstructor()->getMock();
  270. $content = 'azerty';
  271. $this->twig->expects(self::once())
  272. ->method('render')
  273. ->with('/path/to/template.html.twig', ['model' => $model])
  274. ->willReturn($content);
  275. $result = $exporter->render($model);
  276. $this->assertEquals($content, $result);
  277. }
  278. /**
  279. * @see BaseExporter::render()
  280. */
  281. public function testRenderError(): void
  282. {
  283. $exporter = $this->getBaseExporterMockFor('render');
  284. $exporter->method('getTemplatePath')->willReturn('/path/to/template.html.twig');
  285. $model = $this->getMockBuilder(ExportModelInterface::class)->disableOriginalConstructor()->getMock();
  286. $this->twig
  287. ->expects(self::once())
  288. ->method('render')
  289. ->with('/path/to/template.html.twig', ['model' => $model])
  290. ->willThrowException(new SyntaxError('error'));
  291. $this->expectException(\RuntimeException::class);
  292. $exporter->render($model);
  293. }
  294. /**
  295. * @see BaseExporter::encode()
  296. */
  297. public function testEncode(): void
  298. {
  299. $exporter = $this->getBaseExporterMockFor('encode');
  300. $encoder = $this->getMockBuilder(EncoderInterface::class)->getMock();
  301. $this->encoderIterator->expects(self::once())->method('getEncoderFor')->with('pdf')->willReturn($encoder);
  302. $html = '<span>foo</span>';
  303. $content = 'foo';
  304. $encoder->expects(self::once())->method('encode')->with($html)->willReturn($content);
  305. $result = $exporter->encode($html, 'pdf');
  306. $this->assertEquals($content, $result);
  307. }
  308. /**
  309. * @see BaseExporter::getFileBasename()
  310. */
  311. public function testGetFileBasename(): void
  312. {
  313. $exporter = $this->getBaseExporterMockFor('getFileBasename');
  314. $exportRequest = $this->getMockBuilder(ExportRequest::class)->disableOriginalConstructor()->getMock();
  315. $exporter->method('getBasename')->willReturn('base');
  316. $this->assertEquals('base', $exporter->getFileBasename($exportRequest));
  317. }
  318. /**
  319. * @see BaseExporter::getFileType()
  320. */
  321. public function testGetFileType(): void
  322. {
  323. $exporter = $this->getBaseExporterMockFor('getFileType');
  324. $this->assertEquals(FileTypeEnum::UNKNOWN, $exporter->getFileType());
  325. }
  326. }