* @link https://www.oxidmodule.com */ declare(strict_types=1); namespace D3\DataWizard\tests\unit\Application\Model; use D3\DataWizard\Application\Model\Exceptions\ExportFileException; use D3\DataWizard\Application\Model\Exceptions\TaskException; use D3\DataWizard\Application\Model\ExportRenderer\Csv; use D3\DataWizard\Application\Model\ExportRenderer\RendererBridge; use D3\DataWizard\Application\Model\ExportRenderer\RendererInterface; use D3\DataWizard\tests\tools\d3TestExport; use D3\ModCfg\Application\Model\d3filesystem; use D3\ModCfg\Tests\unit\d3ModCfgUnitTestCase; use Doctrine\DBAL\Connection; use Doctrine\DBAL\Driver\Result; use FormManager\Inputs\Hidden; use FormManager\Inputs\Number; use FormManager\Inputs\Radio; use OxidEsales\Eshop\Core\Database\Adapter\Doctrine\Database; use OxidEsales\Eshop\Core\Exception\StandardException; use OxidEsales\Eshop\Core\Registry; use PHPUnit\Framework\MockObject\MockObject; use ReflectionException; class ExportBaseTest extends d3ModCfgUnitTestCase { /** @var d3TestExport */ protected $_oModel; public function setUp(): void { parent::setUp(); $this->_oModel = oxNew(d3TestExport::class); } public function tearDown(): void { parent::tearDown(); unset($this->_oModel); } /** * @covers \D3\DataWizard\Application\Model\ExportBase::getDescription * @test * @throws ReflectionException */ public function canGetDescription() { $this->assertIsString( $this->callMethod( $this->_oModel, 'getDescription' ) ); } /** * @covers \D3\DataWizard\Application\Model\ExportBase::getButtonText * @test * @throws ReflectionException */ public function canGetButtonText() { $this->assertIsString( $this->callMethod( $this->_oModel, 'getButtonText' ) ); } /** * @covers \D3\DataWizard\Application\Model\ExportBase::hasFormElements * @test * @throws ReflectionException * @dataProvider canGetHasFormElementsDataProvider */ public function canGetHasFormElements($formElements, $expected) { $this->setValue($this->_oModel, 'formElements', $formElements); $this->assertSame( $expected, $this->callMethod( $this->_oModel, 'hasFormElements' ) ); } public function canGetHasFormElementsDataProvider(): array { return [ 'hasFormElements' => [['abc', 'def'], true], 'hasNoFormElements' => [[], false], ]; } /** * @covers \D3\DataWizard\Application\Model\ExportBase::getFormElements * @test * @throws ReflectionException * @dataProvider canGetHasFormElementsDataProvider */ public function canGetFormElements($formElements) { $this->setValue($this->_oModel, 'formElements', $formElements); $this->assertSame( $formElements, $this->callMethod( $this->_oModel, 'getFormElements' ) ); } /** * @covers \D3\DataWizard\Application\Model\ExportBase::registerFormElement * @test * @throws ReflectionException * @dataProvider canRegisterFormElementDataProvider */ public function canRegisterFormElement($inputClass) { $oldCount = count($this->getValue($this->_oModel, 'formElements')); /** @var Radio|MockObject $inputMock */ $inputMock = $this->getMockBuilder($inputClass) ->onlyMethods([ 'setTemplate', 'setAttribute', ]) ->getMock(); $inputMock->expects($this->atLeastOnce())->method('setTemplate'); $inputMock->expects($this->atLeastOnce())->method('setAttribute'); $this->callMethod( $this->_oModel, 'registerFormElement', [$inputMock] ); $newCount = count($this->getValue($this->_oModel, 'formElements')); $this->assertGreaterThan($oldCount, $newCount); } /** * @return \string[][] */ public function canRegisterFormElementDataProvider(): array { return [ 'Radio' => [Radio::class], 'Checkbox' => [Radio::class], 'Hidden' => [Hidden::class], ]; } /** * @covers \D3\DataWizard\Application\Model\ExportBase::run * @test * @throws ReflectionException */ public function canRunWithoutFormElements() { $format = 'myFormat'; $path = 'myPath'; /** @var d3TestExport|MockObject $modelMock */ $modelMock = $this->getMockBuilder(d3TestExport::class) ->onlyMethods([ 'hasFormElements', 'executeExport', ]) ->getMock(); $modelMock->expects($this->atLeastOnce())->method('hasFormElements')->willReturn(false); $modelMock->expects($this->atLeastOnce())->method('executeExport')->with($format, $path)->willReturn('some content'); $this->_oModel = $modelMock; $this->callMethod( $this->_oModel, 'run', [$format, $path] ); } /** * @covers \D3\DataWizard\Application\Model\ExportBase::run * @test * @throws ReflectionException * @dataProvider canRunWithFormElementsDataProvider */ public function canRunWithFormElements($elements, $blThrowException) { $format = 'myFormat'; $path = 'myPath'; $expectedException = oxNew(StandardException::class); $modelMock = $this->getMockBuilder(d3TestExport::class) ->onlyMethods([ 'hasFormElements', 'executeExport', 'getFormElements', ]) ->getMock(); $modelMock->expects($this->atLeastOnce())->method('hasFormElements')->willReturn(true); $modelMock->expects($this->exactly((int) !$blThrowException))->method('executeExport')->with($format, $path)->willReturn('some content'); $modelMock->expects($this->atLeastOnce())->method('getFormElements')->willReturn($elements); $this->_oModel = $modelMock; if ($blThrowException) { $this->expectException(get_class($expectedException)); } $this->callMethod( $this->_oModel, 'run', [$format, $path] ); } /** * @return array[] */ public function canRunWithFormElementsDataProvider(): array { /** @var Radio|MockObject $validMock */ $validMock = $this->getMockBuilder(Radio::class) ->onlyMethods(['isValid']) ->getMock(); $validMock->expects($this->atLeastOnce())->method('isValid')->willReturn(true); $invalidField = new Number(null, [ 'required' => true, 'min' => 1, 'max' => 10, 'step' => 5, ]); $invalidField ->setValue(20) ->setErrorMessages(['errorMsgs']); return [ 'validElements' => [[$validMock, $validMock], false], 'invalidElements' => [[$validMock, $invalidField], true], ]; } /** * @covers \D3\DataWizard\Application\Model\ExportBase::executeExport * @test * @throws ReflectionException * @dataProvider canExecuteExportDataProvider */ public function canExecuteExport($path, $throwsException) { /** @var d3filesystem|MockObject $fsMock */ $fsMock = $this->getMockBuilder(d3filesystem::class) ->onlyMethods([ 'startDirectDownload', 'filterFilename', 'trailingslashit', 'createFile', ]) ->getMock(); $fsMock->expects($this->exactly((int) !isset($path)))->method('startDirectDownload')->willReturn(true); $fsMock->method('filterFilename')->willReturnArgument(0); $fsMock->expects($this->exactly((int) isset($path)))->method('trailingslashit')->willReturnArgument(0); $fsMock->expects($this->exactly((int) isset($path)))->method('createFile')->willReturn((bool) !$throwsException); /** @var d3TestExport|MockObject $modelMock */ $modelMock = $this->getMockBuilder(d3TestExport::class) ->onlyMethods([ 'getContent', 'getFileSystem', 'getExportFileName', ]) ->getMock(); $modelMock->expects($this->atLeastOnce())->method('getContent')->willReturn('some content'); $modelMock->expects($this->atLeastOnce())->method('getFileSystem')->willReturn($fsMock); $modelMock->expects($this->atLeastOnce())->method('getExportFileName')->willReturn('exportFileName'); $this->_oModel = $modelMock; if ($path && $throwsException) { $this->expectException(ExportFileException::class); } $this->callMethod( $this->_oModel, 'executeExport', ['CSV', $path] ); } /** * @return array[] */ public function canExecuteExportDataProvider(): array { return [ 'unable to create path for saving file' => ['myPath', true], 'can create path for saving file' => ['myPath', false], 'no path for download' => [null, false], ]; } /** * @covers \D3\DataWizard\Application\Model\ExportBase::getConnection * @test * @throws ReflectionException */ public function canGetConnection() { $this->assertInstanceOf( Connection::class, $this->callMethod( $this->_oModel, 'getConnection' ) ); } /** * @covers \D3\DataWizard\Application\Model\ExportBase::getFileSystem * @test * @throws ReflectionException */ public function canGetFileSystem() { $this->assertInstanceOf( d3filesystem::class, $this->callMethod( $this->_oModel, 'getFileSystem' ) ); } /** * @covers \D3\DataWizard\Application\Model\ExportBase::getRenderer * @test * @throws ReflectionException */ public function canGetRenderer() { /** @var RendererInterface|MockObject $rendererMock */ $rendererMock = $this->getMockBuilder(Csv::class) ->getMock(); /** @var RendererBridge|MockObject $rendererBridgeMock */ $rendererBridgeMock = $this->getMockBuilder(RendererBridge::class) ->onlyMethods(['getRenderer']) ->getMock(); $rendererBridgeMock->expects($this->atLeastOnce())->method('getRenderer')->willReturn($rendererMock); /** @var d3TestExport|MockObject $modelMock */ $modelMock = $this->getMockBuilder(d3TestExport::class) ->onlyMethods([ 'getRendererBridge', ]) ->getMock(); $modelMock->expects($this->atLeastOnce())->method('getRendererBridge')->willReturn($rendererBridgeMock); $this->_oModel = $modelMock; $this->assertSame( $rendererMock, $this->callMethod( $this->_oModel, 'getRenderer', [RendererBridge::FORMAT_CSV] ) ); } /** * @covers \D3\DataWizard\Application\Model\ExportBase::getRendererBridge * @test * @throws ReflectionException */ public function canGetRendererBridge() { $this->assertInstanceOf( RendererBridge::class, $this->callMethod( $this->_oModel, 'getRendererBridge' ) ); } /** * @covers \D3\DataWizard\Application\Model\ExportBase::getFileExtension * @test * @throws ReflectionException */ public function canGetFileExtension() { $format = RendererBridge::FORMAT_CSV; $expected = 'myFileExtension'; /** @var RendererInterface|MockObject $rendererMock */ $rendererMock = $this->getMockBuilder(Csv::class) ->onlyMethods(['getFileExtension']) ->getMock(); $rendererMock->expects($this->atLeastOnce())->method('getFileExtension')->willReturn($expected); /** @var d3TestExport|MockObject $modelMock */ $modelMock = $this->getMockBuilder(d3TestExport::class) ->onlyMethods([ 'getRenderer', ]) ->getMock(); $modelMock->expects($this->atLeastOnce())->method('getRenderer')->with($format)->willReturn($rendererMock); $this->_oModel = $modelMock; $this->assertSame( $expected, $this->callMethod( $this->_oModel, 'getFileExtension', [$format] ) ); } /** * @covers \D3\DataWizard\Application\Model\ExportBase::renderContent * @test * @throws ReflectionException */ public function canRenderContent() { $rows = ['row1', 'row2']; $fieldnames = ['fieldname1', 'fieldname2']; $format = RendererBridge::FORMAT_CSV; $expected = 'myContent'; /** @var RendererInterface|MockObject $rendererMock */ $rendererMock = $this->getMockBuilder(Csv::class) ->onlyMethods(['getContent']) ->getMock(); $rendererMock->expects($this->atLeastOnce())->method('getContent')->with($rows, $fieldnames)->willReturn($expected); /** @var d3TestExport|MockObject $modelMock */ $modelMock = $this->getMockBuilder(d3TestExport::class) ->onlyMethods([ 'getRenderer', ]) ->getMock(); $modelMock->expects($this->atLeastOnce())->method('getRenderer')->with($format)->willReturn($rendererMock); $this->_oModel = $modelMock; $this->assertSame( $expected, $this->callMethod( $this->_oModel, 'renderContent', [$rows, $fieldnames, $format] ) ); } /** * @covers \D3\DataWizard\Application\Model\ExportBase::getExportFilenameBase * @test * @throws ReflectionException */ public function canGetExportFilenameBase() { /** @var d3TestExport|MockObject $modelMock */ $modelMock = $this->getMockBuilder(d3TestExport::class) ->onlyMethods([ 'getTitle', ]) ->getMock(); $modelMock->expects($this->atLeastOnce())->method('getTitle')->willReturn('someTitle'); $this->_oModel = $modelMock; $this->callMethod( $this->_oModel, 'getExportFilenameBase' ); } /** * @covers \D3\DataWizard\Application\Model\ExportBase::getExportFileName * @test * @throws ReflectionException */ public function canGetExportFileName() { $format = RendererBridge::FORMAT_CSV; /** @var d3TestExport|MockObject $modelMock */ $modelMock = $this->getMockBuilder(d3TestExport::class) ->onlyMethods([ 'getExportFilenameBase', 'getFileExtension', ]) ->getMock(); $modelMock->expects($this->atLeastOnce())->method('getExportFilenameBase')->willReturn('base'); $modelMock->expects($this->atLeastOnce())->method('getFileExtension')->with($format)->willReturn('extension'); $this->_oModel = $modelMock; $this->assertMatchesRegularExpression( '/^base_(\d{4})-(\d{2})-(\d{2})_(\d{2})-(\d{2})-(\d{2})\.extension$/m', $this->callMethod( $this->_oModel, 'getExportFileName', [$format] ) ); } /** * @covers \D3\DataWizard\Application\Model\ExportBase::getExportData * @test * @throws ReflectionException * @dataProvider canGetExportDataDataProvider */ public function canGetExportData($query, $throwsException, $dbResult) { /** @var Result|MockObject $resultMock */ $resultMock = $this->getMockBuilder(Result::class) ->onlyMethods(get_class_methods(Result::class)) ->getMock(); $resultMock->method('fetchAllAssociative')->willReturn($dbResult); /** @var Database|MockObject $connectionMock */ $connectionMock = $this->getMockBuilder(Connection::class) ->disableOriginalConstructor() ->onlyMethods(['executeQuery']) ->getMock(); $connectionMock->expects($this->exactly((int) !$throwsException))->method('executeQuery')->willReturn($resultMock); /** @var d3TestExport|MockObject $modelMock */ $modelMock = $this->getMockBuilder(d3TestExport::class) ->onlyMethods([ 'getConnection', ]) ->getMock(); $modelMock->expects($this->exactly((int) !$throwsException))->method('getConnection')->willReturn($connectionMock); $this->_oModel = $modelMock; try { $result = $this->callMethod( $this->_oModel, 'getExportData', [[$query], ['param1', 'param2']] ); $this->assertSame( [ [ [ 'field1' => 'content1', 'field2' => 'content2', ], ], [ 'field1', 'field2', ], ], $result ); } catch (TaskException $e) { if ($throwsException) { $this->assertStringContainsString('NOEXPORTSELECT', $e->getMessage()); } elseif (!count($dbResult)) { $this->assertStringContainsString('kein Inhalt', $e->getMessage()); } } } /** * @return array[] */ public function canGetExportDataDataProvider(): array { return [ 'not SELECT throws exception' => [' UPDATE 1', true, []], 'empty SELECT' => [' SELECT 1', false, []], 'fulfilled SELECT' => [' SELECT 1', false, [['field1' => 'content1', 'field2' => 'content2']]], ]; } /** * @covers \D3\DataWizard\Application\Model\ExportBase::getContent * @test * @throws ReflectionException */ public function canGetContent() { /** @var d3TestExport|MockObject $modelMock */ $modelMock = $this->getMockBuilder(d3TestExport::class) ->onlyMethods([ 'getQuery', 'getExportData', 'renderContent', ]) ->getMock(); $modelMock->expects($this->atLeastOnce())->method('getQuery')->willReturn(['SELECT 1', ['arg1', 'arg2']]); $modelMock->expects($this->atLeastOnce())->method('getExportData')->willReturn([[1, 2], ['field1', 'field2']]); $modelMock->expects($this->atLeastOnce())->method('renderContent')->willReturn('some content'); $this->_oModel = $modelMock; $this->assertSame( 'some content', $this->callMethod( $this->_oModel, 'getContent', ['CSV'] ) ); } }