BaseExporterTest.php 15 KB

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