diff --git a/Application/Controller/Admin/d3ActionWizard.php b/Application/Controller/Admin/d3ActionWizard.php
index 3c4e5a4..c15ec84 100644
--- a/Application/Controller/Admin/d3ActionWizard.php
+++ b/Application/Controller/Admin/d3ActionWizard.php
@@ -23,6 +23,7 @@ use D3\ModCfg\Application\Model\Exception\d3_cfg_mod_exception;
use D3\ModCfg\Application\Model\Exception\d3ShopCompatibilityAdapterException;
use Doctrine\DBAL\DBALException;
use OxidEsales\Eshop\Application\Controller\Admin\AdminDetailsController;
+use OxidEsales\Eshop\Core\Config;
use OxidEsales\Eshop\Core\Exception\DatabaseConnectionException;
use OxidEsales\Eshop\Core\Exception\DatabaseErrorException;
use OxidEsales\Eshop\Core\Exception\StandardException;
@@ -79,7 +80,7 @@ class d3ActionWizard extends AdminDetailsController
[ $queryString, $parameters ] = $action->getQuery();
- if (Registry::getConfig()->getConfigParam('d3datawizard_debug')) {
+ if ($this->d3GetConfig()->getConfigParam('d3datawizard_debug')) {
throw oxNew(
DebugException::class,
d3database::getInstance()->getPreparedStatementQuery($queryString, $parameters)
@@ -89,6 +90,14 @@ class d3ActionWizard extends AdminDetailsController
$action->run();
}
+ /**
+ * @return Config
+ */
+ public function d3GetConfig()
+ {
+ return Registry::getConfig();
+ }
+
public function getUserMessages()
{
return null;
diff --git a/Application/Controller/Admin/d3ExportWizard.php b/Application/Controller/Admin/d3ExportWizard.php
index d38e678..049a24e 100644
--- a/Application/Controller/Admin/d3ExportWizard.php
+++ b/Application/Controller/Admin/d3ExportWizard.php
@@ -25,6 +25,7 @@ use D3\ModCfg\Application\Model\Exception\d3_cfg_mod_exception;
use D3\ModCfg\Application\Model\Exception\d3ShopCompatibilityAdapterException;
use Doctrine\DBAL\DBALException;
use OxidEsales\Eshop\Application\Controller\Admin\AdminDetailsController;
+use OxidEsales\Eshop\Core\Config;
use OxidEsales\Eshop\Core\Exception\DatabaseConnectionException;
use OxidEsales\Eshop\Core\Exception\DatabaseErrorException;
use OxidEsales\Eshop\Core\Exception\StandardException;
@@ -87,7 +88,7 @@ class d3ExportWizard extends AdminDetailsController
[ $queryString, $parameters ] = $export->getQuery();
- if (Registry::getConfig()->getConfigParam('d3datawizard_debug')) {
+ if ($this->d3GetConfig()->getConfigParam('d3datawizard_debug')) {
throw oxNew(
DebugException::class,
d3database::getInstance()->getPreparedStatementQuery($queryString, $parameters)
@@ -97,6 +98,14 @@ class d3ExportWizard extends AdminDetailsController
$export->run(Registry::getRequest()->getRequestEscapedParameter('format'));
}
+ /**
+ * @return Config
+ */
+ public function d3GetConfig()
+ {
+ return Registry::getConfig();
+ }
+
public function getUserMessages()
{
return null;
diff --git a/Application/Model/ActionBase.php b/Application/Model/ActionBase.php
index 1285f34..5bb651c 100644
--- a/Application/Model/ActionBase.php
+++ b/Application/Model/ActionBase.php
@@ -19,6 +19,7 @@ use D3\DataWizard\Application\Model\Exceptions\InputUnvalidException;
use FormManager\Inputs\Checkbox;
use FormManager\Inputs\Input;
use FormManager\Inputs\Radio;
+use OxidEsales\Eshop\Core\Database\Adapter\DatabaseInterface;
use OxidEsales\Eshop\Core\DatabaseProvider;
use OxidEsales\Eshop\Core\Exception\DatabaseConnectionException;
use OxidEsales\Eshop\Core\Exception\DatabaseErrorException;
@@ -76,7 +77,7 @@ abstract class ActionBase implements QueryBase
);
}
- $affected = DatabaseProvider::getDb( DatabaseProvider::FETCH_MODE_ASSOC )->execute( $queryString, $parameters );
+ $affected = $this->d3GetDb()->execute( $queryString, $parameters );
throw oxNew(
Exceptions\TaskException::class,
@@ -90,6 +91,15 @@ abstract class ActionBase implements QueryBase
);
}
+ /**
+ * @return DatabaseInterface|null
+ * @throws DatabaseConnectionException
+ */
+ public function d3GetDb()
+ {
+ return DatabaseProvider::getDb( DatabaseProvider::FETCH_MODE_ASSOC );
+ }
+
/**
* @return string
*/
@@ -103,15 +113,12 @@ abstract class ActionBase implements QueryBase
*/
public function registerFormElement(Input $input)
{
- switch (get_class($input)) {
- case Radio::class:
- case Checkbox::class:
- $input->setTemplate('
{{ input }} {{ label }}
');
- $input->setAttribute('class', 'form-check-input');
- break;
- default:
- $input->setTemplate('{{ label }} {{ input }}
');
- $input->setAttribute('class', 'form-control');
+ if ($input instanceof Radio || $input instanceof Checkbox) {
+ $input->setTemplate('{{ input }} {{ label }}
');
+ $input->setAttribute('class', 'form-check-input');
+ } else {
+ $input->setTemplate('{{ label }} {{ input }}
');
+ $input->setAttribute('class', 'form-control');
}
$this->formElements[] = $input;
}
diff --git a/Application/Model/Configuration.php b/Application/Model/Configuration.php
index 62caa45..90208c5 100644
--- a/Application/Model/Configuration.php
+++ b/Application/Model/Configuration.php
@@ -149,7 +149,13 @@ class Configuration
*/
public function getActionById($id) : ActionBase
{
- return $this->getAllActions()[$id];
+ $allActions = $this->getAllActions();
+
+ if (false == $allActions[$id]) {
+ throw oxNew(DataWizardException::class, 'no action with id '.$id);
+ }
+
+ return $allActions[$id];
}
/**
diff --git a/Application/Model/ExportBase.php b/Application/Model/ExportBase.php
index 480bab2..02c0eab 100644
--- a/Application/Model/ExportBase.php
+++ b/Application/Model/ExportBase.php
@@ -69,23 +69,7 @@ abstract class ExportBase implements QueryBase
}
}
- [ $rows, $fieldNames ] = $this->getExportData( $this->getQuery() );
-
- $content = $this->renderContent($rows, $fieldNames, $format);
-
- /** @var $oFS d3filesystem */
- $oFS = oxNew( d3filesystem::class );
- if (is_null($path)) {
- $oFS->startDirectDownload( $oFS->filterFilename( $this->getExportFileName( $format ) ), $content );
- } else {
- $filePath = $oFS->trailingslashit($path).$oFS->filterFilename( $this->getExportFileName( $format ) );
- if (false === $oFS->createFile($filePath, $content,true)) {
- throw oxNew(ExportFileException::class, $filePath);
- }
- return $filePath;
- }
-
- return '';
+ return $this->executeExport($format, $path);
}
/**
@@ -180,7 +164,7 @@ abstract class ExportBase implements QueryBase
);
}
- $rows = DatabaseProvider::getDb( DatabaseProvider::FETCH_MODE_ASSOC )->getAll( $queryString, $parameters );
+ $rows = $this->d3GetDb()->getAll( $queryString, $parameters );
if ( count( $rows ) <= 0 ) {
throw oxNew(
@@ -200,15 +184,12 @@ abstract class ExportBase implements QueryBase
*/
public function registerFormElement(Input $input)
{
- switch (get_class($input)) {
- case Radio::class:
- case Checkbox::class:
- $input->setTemplate('{{ input }} {{ label }}
');
- $input->setAttribute('class', 'form-check-input');
- break;
- default:
- $input->setTemplate('{{ label }} {{ input }}
');
- $input->setAttribute('class', 'form-control');
+ if ($input instanceof Radio || $input instanceof Checkbox) {
+ $input->setTemplate('{{ input }} {{ label }}
');
+ $input->setAttribute('class', 'form-check-input');
+ } else {
+ $input->setTemplate('{{ label }} {{ input }}
');
+ $input->setAttribute('class', 'form-control');
}
$this->formElements[] = $input;
}
@@ -228,4 +209,54 @@ abstract class ExportBase implements QueryBase
{
return $this->formElements;
}
+
+ /**
+ * @param string $format
+ * @param $path
+ * @return string
+ * @throws DBALException
+ * @throws DatabaseConnectionException
+ * @throws DatabaseErrorException
+ * @throws Exceptions\NoSuitableRendererException
+ * @throws StandardException
+ * @throws d3ShopCompatibilityAdapterException
+ * @throws d3_cfg_mod_exception
+ */
+ protected function executeExport(string $format, $path): string
+ {
+ [$rows, $fieldNames] = $this->getExportData($this->getQuery());
+
+ $content = $this->renderContent($rows, $fieldNames, $format);
+
+ /** @var $oFS d3filesystem */
+ $oFS = $this->getFileSystem();
+ if (is_null($path)) {
+ $oFS->startDirectDownload($oFS->filterFilename($this->getExportFileName($format)), $content);
+ } else {
+ $filePath = $oFS->trailingslashit($path) . $oFS->filterFilename($this->getExportFileName($format));
+ if (false === $oFS->createFile($filePath, $content, true)) {
+ throw oxNew(ExportFileException::class, $filePath);
+ }
+ return $filePath;
+ }
+
+ return '';
+ }
+
+ /**
+ * @return \OxidEsales\Eshop\Core\Database\Adapter\DatabaseInterface|null
+ * @throws DatabaseConnectionException
+ */
+ protected function d3GetDb(): ?\OxidEsales\Eshop\Core\Database\Adapter\DatabaseInterface
+ {
+ return DatabaseProvider::getDb(DatabaseProvider::FETCH_MODE_ASSOC);
+ }
+
+ /**
+ * @return d3filesystem|mixed
+ */
+ protected function getFileSystem()
+ {
+ return oxNew(d3filesystem::class);
+ }
}
\ No newline at end of file
diff --git a/Application/Model/ExportRenderer/Csv.php b/Application/Model/ExportRenderer/Csv.php
index 549f6d8..38f38b6 100644
--- a/Application/Model/ExportRenderer/Csv.php
+++ b/Application/Model/ExportRenderer/Csv.php
@@ -19,6 +19,7 @@ use D3\DataWizard\Application\Model\Exceptions\RenderException;
use League\Csv\EncloseField;
use League\Csv\Exception;
use League\Csv\Writer;
+use OxidEsales\Eshop\Core\Config;
use OxidEsales\Eshop\Core\Registry;
class Csv implements RendererInterface
@@ -59,13 +60,13 @@ class Csv implements RendererInterface
EncloseField::addTo($csv, "\t\x1f");
- $sEncloser = Registry::getConfig()->getConfigParam('sGiCsvFieldEncloser');
+ $sEncloser = $this->d3GetConfig()->getConfigParam('sGiCsvFieldEncloser');
if (false == $sEncloser) {
$sEncloser = '"';
}
$csv->setEnclosure($sEncloser);
- $sDelimiter = Registry::getConfig()->getConfigParam('sCSVSign');
+ $sDelimiter = $this->d3GetConfig()->getConfigParam('sCSVSign');
if (false == $sDelimiter) {
$sDelimiter = ';';
}
@@ -81,4 +82,12 @@ class Csv implements RendererInterface
{
return 'D3_DATAWIZARD_EXPORT_FORMAT_CSV';
}
+
+ /**
+ * @return Config
+ */
+ public function d3GetConfig()
+ {
+ return Registry::getConfig();
+ }
}
\ No newline at end of file
diff --git a/Application/Model/ExportRenderer/Pretty.php b/Application/Model/ExportRenderer/Pretty.php
index 9029853..8700d2f 100644
--- a/Application/Model/ExportRenderer/Pretty.php
+++ b/Application/Model/ExportRenderer/Pretty.php
@@ -27,10 +27,19 @@ class Pretty implements RendererInterface
*/
public function getContent($rows, $fieldNames) : string
{
- $renderer = oxNew(ArrayToTextTable::class, $rows);
+ $renderer = $this->getArrayToTextTableInstance($rows);
return $renderer->getTable();
}
+ /**
+ * @param $rows
+ * @return ArrayToTextTable
+ */
+ public function getArrayToTextTableInstance($rows)
+ {
+ return oxNew(ArrayToTextTable::class, $rows);
+ }
+
/**
* @return string
*/
diff --git a/composer.json b/composer.json
index 188e9c2..78a9bc3 100644
--- a/composer.json
+++ b/composer.json
@@ -31,6 +31,9 @@
"mathieuviossat/arraytotexttable": "^1.0",
"form-manager/form-manager": "^5.1 || ^6.1"
},
+ "require-dev": {
+ "oxid-esales/oxideshop-ce": "6.8 - 6.9"
+ },
"extra": {
"oxideshop": {
"blacklist-filter": [
diff --git a/tests/.gitignore b/tests/.gitignore
new file mode 100644
index 0000000..89bffeb
--- /dev/null
+++ b/tests/.gitignore
@@ -0,0 +1,2 @@
+reports
+.phpunit.result.cache
diff --git a/tests/README.md b/tests/README.md
new file mode 100644
index 0000000..2e8a767
--- /dev/null
+++ b/tests/README.md
@@ -0,0 +1,52 @@
+# D3 Datawizard Tests
+
+## Requirements
+
+Both unit and acceptance tests require OXID Testing Library installed.
+See https://github.com/OXID-eSales/testing_library.
+
+### Configuration
+
+Please install the packages listed in the composer.json in "require-dev". Unfortunately Composer does not provide an automatic installation.
+
+Here is an example of Testing Library configuration file `oxideshop/test_config.yml`
+
+```
+# This file is auto-generated during the composer install
+mandatory_parameters:
+ shop_path: /var/www/oxideshop/source
+ shop_tests_path: /var/www/oxideshop/tests
+ partial_module_paths: d3/datawizard
+optional_parameters:
+ shop_url: null
+ shop_serial: ''
+ enable_varnish: false
+ is_subshop: false
+ install_shop: false
+ remote_server_dir: null
+ shop_setup_path: null
+ restore_shop_after_tests_suite: false
+ test_database_name: null
+ restore_after_acceptance_tests: false
+ restore_after_unit_tests: false
+ tmp_path: /tmp/oxid_test_library/
+ database_restoration_class: DatabaseRestorer
+ activate_all_modules: false
+ run_tests_for_shop: false
+ run_tests_for_modules: true
+ screen_shots_path: null
+ screen_shots_url: null
+ browser_name: firefox
+ selenium_server_ip: 127.0.0.1
+ selenium_server_port: '4444'
+ additional_test_paths: null
+```
+
+## Unit Tests
+
+To execute unit tests run the following:
+
+```
+cd /var/www/oxideshop/
+vendor/bin/runtests
+```
diff --git a/tests/additional.inc.php b/tests/additional.inc.php
new file mode 100755
index 0000000..84c8ac5
--- /dev/null
+++ b/tests/additional.inc.php
@@ -0,0 +1,39 @@
+
+ * @link https://www.oxidmodule.com
+ */
+
+// Include datawizard test config
+namespace D3\DataWizard\tests;
+
+use D3\ModCfg\Tests\additional_abstract;
+use Exception;
+use OxidEsales\Eshop\Core\Exception\StandardException;
+
+include(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'd3datawizard_config.php');
+
+class additional extends additional_abstract
+{
+ /**
+ * additional constructor.
+ * @throws StandardException
+ */
+ public function __construct()
+ {
+ if (D3DATAWIZARD_REQUIRE_MODCFG) {
+ $this->reactivateModCfg();
+ }
+ }
+}
+
+try {
+ d3GetModCfgDIC()->get(additional::class);
+} catch (Exception $e) {}
\ No newline at end of file
diff --git a/tests/d3datawizard_config.php b/tests/d3datawizard_config.php
new file mode 100755
index 0000000..e4e6aab
--- /dev/null
+++ b/tests/d3datawizard_config.php
@@ -0,0 +1,15 @@
+
+ * @link https://www.oxidmodule.com
+ */
+
+define('D3DATAWIZARD_REQUIRE_MODCFG', true);
+
diff --git a/tests/phpunit.xml b/tests/phpunit.xml
new file mode 100644
index 0000000..6c09de6
--- /dev/null
+++ b/tests/phpunit.xml
@@ -0,0 +1,27 @@
+
+
+
+ ../Application
+ ../Modules
+ ../public
+ ../Setup
+
+
+
+
+
+
diff --git a/tests/tools/d3TestAction.php b/tests/tools/d3TestAction.php
new file mode 100644
index 0000000..746624e
--- /dev/null
+++ b/tests/tools/d3TestAction.php
@@ -0,0 +1,18 @@
+
+ * @link https://www.oxidmodule.com
+ */
+
+declare(strict_types=1);
+
+namespace D3\DataWizard\tests\unit\Application\Controller\Admin;
+
+use D3\DataWizard\Application\Controller\Admin\d3ActionWizard;
+use D3\DataWizard\Application\Model\Configuration;
+use D3\DataWizard\Application\Model\Exceptions\DebugException;
+use D3\DataWizard\Application\Model\ExportRenderer\RendererBridge;
+use D3\DataWizard\tests\tools\d3TestAction;
+use OxidEsales\Eshop\Core\Config;
+use OxidEsales\Eshop\Core\Registry;
+use OxidEsales\Eshop\Core\Request;
+use PHPUnit\Framework\MockObject\MockObject;
+use ReflectionException;
+
+class d3ActionWizardTest extends d3AdminControllerTest
+{
+ /** @var d3ActionWizard */
+ protected $_oController;
+
+ protected $testClassName = d3ActionWizard::class;
+
+ public function setUp() : void
+ {
+ parent::setUp();
+
+ $this->_oController = oxNew($this->testClassName);
+ }
+
+ /**
+ * @covers \D3\DataWizard\Application\Controller\Admin\d3ActionWizard::getGroups()
+ * @test
+ * @throws ReflectionException
+ */
+ public function canGetGroups()
+ {
+ $expected = ['expected' => 'array'];
+ /** @var Configuration|MockObject $configurationMock */
+ $configurationMock = $this->getMockBuilder(Configuration::class)
+ ->onlyMethods(['getActionGroups'])
+ ->getMock();
+ $configurationMock->expects($this->atLeastOnce())->method('getActionGroups')->willReturn($expected);
+
+ $this->setValue($this->_oController, 'configuration', $configurationMock);
+
+ $this->assertSame(
+ $expected,
+ $this->callMethod(
+ $this->_oController,
+ 'getGroups'
+ )
+ );
+ }
+
+ /**
+ * @covers \D3\DataWizard\Application\Controller\Admin\d3ActionWizard::getGroupTasks()
+ * @test
+ * @throws ReflectionException
+ * @dataProvider canGetGroupTasksDataProvider
+ */
+ public function canGetGroupTasks($argument)
+ {
+ $expected = ['expected' => 'array'];
+ /** @var Configuration|MockObject $configurationMock */
+ $configurationMock = $this->getMockBuilder(Configuration::class)
+ ->onlyMethods(['getActionsByGroup'])
+ ->getMock();
+ $configurationMock->expects($this->atLeastOnce())->method('getActionsByGroup')->with($argument)->willReturn($expected);
+
+ $this->setValue($this->_oController, 'configuration', $configurationMock);
+
+ $this->assertSame(
+ $expected,
+ $this->callMethod(
+ $this->_oController,
+ 'getGroupTasks',
+ [$argument]
+ )
+ );
+ }
+
+ /**
+ * @return array
+ */
+ public function canGetGroupTasksDataProvider(): array
+ {
+ return [
+ ['test1'],
+ ['test2']
+ ];
+ }
+
+ /**
+ * @covers \D3\DataWizard\Application\Controller\Admin\d3ActionWizard::execute()
+ * @test
+ * @throws ReflectionException
+ * @dataProvider executePassDataProvider
+ */
+ public function executePass($blDebug)
+ {
+ /** @var Request|MockObject $requestMock */
+ $requestMock = $this->getMockBuilder(get_class(Registry::getRequest()))
+ ->onlyMethods(['getRequestEscapedParameter'])
+ ->getMock();
+ $requestMock->expects($this->any())->method('getRequestEscapedParameter')->willReturnCallback([$this, 'executePassRequestCallback']);
+ Registry::set(Request::class, $requestMock);
+
+ /** @var Config|MockObject $configMock */
+ $configMock = $this->getMockBuilder(Config::class)
+ ->onlyMethods(['getConfigParam'])
+ ->getMock();
+ $configMock->expects($this->atLeastOnce())->method('getConfigParam')->willReturnCallback(
+ function ($argName) use ($blDebug) {
+ switch ($argName) {
+ case 'd3datawizard_debug':
+ return $blDebug;
+ default:
+ return Registry::getConfig()->getConfigParam($argName);
+ }
+ }
+ );
+
+ /** @var d3ActionWizard|MockObject $controllerMock */
+ $controllerMock = $this->getMockBuilder(d3ActionWizard::class)
+ ->onlyMethods(['d3GetConfig'])
+ ->getMock();
+ $controllerMock->method('d3GetConfig')->willReturn($configMock);
+ $this->_oController = $controllerMock;
+
+ /** @var d3TestAction|MockObject $actionMock */
+ $actionMock = $this->getMockBuilder(d3TestAction::class)
+ ->onlyMethods([
+ 'getQuery',
+ 'run'
+ ])
+ ->getMock();
+ $actionMock->expects($this->atLeastOnce())->method('getQuery')->willReturn(['SELECT 1', ['1']]);
+ $actionMock->expects($this->exactly((int) !$blDebug))->method('run')->willReturn(true);
+
+ /** @var Configuration|MockObject $configurationMock */
+ $configurationMock = $this->getMockBuilder(Configuration::class)
+ ->onlyMethods(['getActionById'])
+ ->disableOriginalConstructor()
+ ->getMock();
+ $configurationMock->expects($this->atLeastOnce())->method('getActionById')->with('testTaskId')->willReturn($actionMock);
+ $this->setValue($this->_oController, 'configuration', $configurationMock);
+
+ if ($blDebug) {
+ $this->expectException(DebugException::class);
+ }
+
+ $this->callMethod(
+ $this->_oController,
+ 'execute'
+ );
+ }
+
+ public function executePassRequestCallback($varName)
+ {
+ switch ($varName) {
+ case 'taskid':
+ return 'testTaskId';
+ case 'format':
+ return RendererBridge::FORMAT_CSV;
+ default:
+ return oxNew(Request::class)->getRequestEscapedParameter($varName);
+ }
+ }
+
+ /**
+ * @return array
+ */
+ public function executePassDataProvider(): array
+ {
+ return [
+ 'no debug' => [false],
+ 'debug' => [true],
+ ];
+ }
+}
\ No newline at end of file
diff --git a/tests/unit/Application/Controller/Admin/d3AdminControllerTest.php b/tests/unit/Application/Controller/Admin/d3AdminControllerTest.php
new file mode 100644
index 0000000..29aa527
--- /dev/null
+++ b/tests/unit/Application/Controller/Admin/d3AdminControllerTest.php
@@ -0,0 +1,262 @@
+
+ * @link https://www.oxidmodule.com
+ */
+
+declare(strict_types=1);
+
+namespace D3\DataWizard\tests\unit\Application\Controller\Admin;
+
+use D3\DataWizard\Application\Controller\Admin\d3ActionWizard;
+use D3\DataWizard\Application\Controller\Admin\d3ExportWizard;
+use D3\DataWizard\Application\Model\Configuration;
+use D3\DataWizard\Application\Model\Exceptions\DataWizardException;
+use D3\DataWizard\Application\Model\Exceptions\DebugException;
+use D3\DataWizard\tests\tools\d3TestAction;
+use D3\ModCfg\Tests\unit\d3ModCfgUnitTestCase;
+use Doctrine\DBAL\DBALException;
+use OxidEsales\Eshop\Core\Config;
+use OxidEsales\Eshop\Core\Exception\DatabaseErrorException;
+use OxidEsales\Eshop\Core\Registry;
+use OxidEsales\Eshop\Core\Request;
+use OxidEsales\Eshop\Core\UtilsView;
+use PHPUnit\Framework\MockObject\MockObject;
+use Psr\Log\LoggerInterface;
+use ReflectionException;
+
+abstract class d3AdminControllerTest extends d3ModCfgUnitTestCase
+{
+ /** @var d3ActionWizard|d3ExportWizard */
+ protected $_oController;
+
+ protected $testClassName;
+
+ public function tearDown() : void
+ {
+ parent::tearDown();
+
+ unset($this->_oController);
+ }
+
+ /**
+ * @covers \D3\DataWizard\Application\Controller\Admin\d3ActionWizard::__construct
+ * @covers \D3\DataWizard\Application\Controller\Admin\d3ExportWizard::__construct
+ * @test
+ * @throws ReflectionException
+ */
+ public function testConstructor()
+ {
+ $this->setValue($this->_oController, 'configuration', null);
+
+ $this->callMethod(
+ $this->_oController,
+ '__construct'
+ );
+
+ $this->assertInstanceOf(
+ Configuration::class,
+ $this->getValue(
+ $this->_oController,
+ 'configuration'
+ )
+ );
+ }
+
+ /**
+ * @covers \D3\DataWizard\Application\Controller\Admin\d3ActionWizard::runTask()
+ * @covers \D3\DataWizard\Application\Controller\Admin\d3ExportWizard::runTask()
+ * @test
+ * @throws ReflectionException
+ */
+ public function runTaskPass()
+ {
+ /** @var d3ActionWizard|d3ExportWizard|MockObject $controllerMock */
+ $controllerMock = $this->getMockBuilder($this->testClassName)
+ ->onlyMethods(['execute'])
+ ->getMock();
+ $controllerMock->expects($this->once())->method('execute')->willReturn(true);
+
+ $this->_oController = $controllerMock;
+
+ $this->callMethod(
+ $this->_oController,
+ 'runTask'
+ );
+ }
+
+ /**
+ * @covers \D3\DataWizard\Application\Controller\Admin\d3ActionWizard::runTask()
+ * @covers \D3\DataWizard\Application\Controller\Admin\d3ExportWizard::runTask()
+ * @test
+ * @param $exceptionClass
+ * @throws ReflectionException
+ * @dataProvider runTaskFailedDataProvider
+ */
+ public function runTaskFailed($exceptionClass)
+ {
+ /** @var DataWizardException|DBALException|DatabaseErrorException|MockObject $exceptionMock */
+ $exceptionMock = $this->getMockBuilder($exceptionClass)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->setValue($exceptionMock, 'message', 'exc_msg');
+
+ /** @var d3ActionWizard|d3ExportWizard|MockObject $controllerMock */
+ $controllerMock = $this->getMockBuilder($this->testClassName)
+ ->onlyMethods(['execute'])
+ ->getMock();
+ $controllerMock->expects($this->once())->method('execute')->willThrowException($exceptionMock);
+
+ /** @var LoggerInterface|MockObject $loggerMock */
+ $loggerMock = $this->getMockBuilder(get_class(Registry::getLogger()))
+ ->onlyMethods(['error'])
+ ->disableOriginalConstructor()
+ ->getMock();
+ $loggerMock->expects($this->atLeastOnce())->method('error')->with('exc_msg')->willReturn(true);
+ Registry::set('logger', $loggerMock);
+
+ /** @var UtilsView|MockObject $utilsViewMock */
+ $utilsViewMock = $this->getMockBuilder(get_class(Registry::getUtilsView()))
+ ->onlyMethods(['addErrorToDisplay'])
+ ->getMock();
+ $utilsViewMock->expects($this->atLeastOnce())->method('addErrorToDisplay')->with($exceptionMock)->willReturn(true);
+ Registry::set(UtilsView::class, $utilsViewMock);
+
+ $this->_oController = $controllerMock;
+
+ $this->callMethod(
+ $this->_oController,
+ 'runTask'
+ );
+ }
+
+ /**
+ * @return \string[][]
+ */
+ public function runTaskFailedDataProvider(): array
+ {
+ return [
+ [DataWizardException::class],
+ [DBALException::class],
+ [DatabaseErrorException::class],
+ ];
+ }
+
+ /**
+ * @covers \D3\DataWizard\Application\Controller\Admin\d3ActionWizard::execute()
+ * @covers \D3\DataWizard\Application\Controller\Admin\d3ExportWizard::execute()
+ * @test
+ * @throws ReflectionException
+ * @dataProvider executePassDataProvider
+ */
+ public function executePass($blDebug)
+ {
+ /** @var Request|MockObject $requestMock */
+ $requestMock = $this->getMockBuilder(get_class(Registry::getRequest()))
+ ->onlyMethods(['getRequestEscapedParameter'])
+ ->getMock();
+ $requestMock->expects($this->atLeastOnce())->method('getRequestEscapedParameter')->with('taskid')->willReturn('testTaskId');
+ Registry::set(Request::class, $requestMock);
+
+ /** @var d3TestAction|MockObject $actionMock */
+ $actionMock = $this->getMockBuilder(d3TestAction::class)
+ ->onlyMethods([
+ 'getQuery',
+ 'run'
+ ])
+ ->getMock();
+ $actionMock->expects($this->atLeastOnce())->method('getQuery')->willReturn(['SELECT 1', ['1']]);
+ $actionMock->expects($this->exactly((int) !$blDebug))->method('run')->willReturn(true);
+
+ /** @var Configuration|MockObject $configurationMock */
+ $configurationMock = $this->getMockBuilder(Configuration::class)
+ ->onlyMethods(['getActionById'])
+ ->disableOriginalConstructor()
+ ->getMock();
+ $configurationMock->expects($this->atLeastOnce())->method('getActionById')->with('testTaskId')->willReturn($actionMock);
+ $this->setValue($this->_oController, 'configuration', $configurationMock);
+
+ /** @var Config|MockObject $configMock */
+ $configMock = $this->getMockBuilder(Config::class)
+ ->onlyMethods(['getConfigParam'])
+ ->getMock();
+ $configMock->expects($this->atLeastOnce())->method('getConfigParam')->willReturn($blDebug);
+ Registry::set(Config::class, $configMock);
+
+ if ($blDebug) {
+ $this->expectException(DebugException::class);
+ }
+
+ $this->callMethod(
+ $this->_oController,
+ 'execute'
+ );
+ }
+
+ /**
+ * @return array
+ */
+ public function executePassDataProvider(): array
+ {
+ return [
+ 'no debug' => [false],
+ 'debug' => [true],
+ ];
+ }
+
+ /**
+ * @covers \D3\DataWizard\Application\Controller\Admin\d3ActionWizard::getUserMessages()
+ * @covers \D3\DataWizard\Application\Controller\Admin\d3ExportWizard::getUserMessages()
+ * @test
+ * @throws ReflectionException
+ */
+ public function canGetUserMessages()
+ {
+ $this->assertNull(
+ $this->callMethod(
+ $this->_oController,
+ 'getUserMessages'
+ )
+ );
+ }
+
+ /**
+ * @covers \D3\DataWizard\Application\Controller\Admin\d3ActionWizard::getHelpURL()
+ * @covers \D3\DataWizard\Application\Controller\Admin\d3ExportWizard::getHelpURL()
+ * @test
+ * @throws ReflectionException
+ */
+ public function canGetHelpUrl()
+ {
+ $this->assertNull(
+ $this->callMethod(
+ $this->_oController,
+ 'getHelpURL'
+ )
+ );
+ }
+
+ /**
+ * @covers \D3\DataWizard\Application\Controller\Admin\d3ExportWizard::d3GetConfig
+ * @covers \D3\DataWizard\Application\Controller\Admin\d3ActionWizard::d3GetConfig
+ * @test
+ * @throws ReflectionException
+ */
+ public function canGetConfig()
+ {
+ $this->assertInstanceOf(
+ Config::class,
+ $this->callMethod(
+ $this->_oController,
+ 'd3GetConfig'
+ )
+ );
+ }
+}
\ No newline at end of file
diff --git a/tests/unit/Application/Controller/Admin/d3ExportWizardTest.php b/tests/unit/Application/Controller/Admin/d3ExportWizardTest.php
new file mode 100644
index 0000000..e5cccf3
--- /dev/null
+++ b/tests/unit/Application/Controller/Admin/d3ExportWizardTest.php
@@ -0,0 +1,195 @@
+
+ * @link https://www.oxidmodule.com
+ */
+
+declare(strict_types=1);
+
+namespace D3\DataWizard\tests\unit\Application\Controller\Admin;
+
+use D3\DataWizard\Application\Controller\Admin\d3ExportWizard;
+use D3\DataWizard\Application\Model\Configuration;
+use D3\DataWizard\Application\Model\Exceptions\DebugException;
+use D3\DataWizard\Application\Model\ExportRenderer\RendererBridge;
+use D3\DataWizard\tests\tools\d3TestAction;
+use D3\DataWizard\tests\tools\d3TestExport;
+use OxidEsales\Eshop\Core\Config;
+use OxidEsales\Eshop\Core\Registry;
+use OxidEsales\Eshop\Core\Request;
+use PHPUnit\Framework\MockObject\MockObject;
+use ReflectionException;
+
+class d3ExportWizardTest extends d3AdminControllerTest
+{
+ /** @var d3ExportWizard */
+ protected $_oController;
+
+ protected $testClassName = d3ExportWizard::class;
+
+ public function setUp() : void
+ {
+ parent::setUp();
+
+ $this->_oController = oxNew($this->testClassName);
+ }
+
+ /**
+ * @covers \D3\DataWizard\Application\Controller\Admin\d3ExportWizard::getGroups()
+ * @test
+ * @throws ReflectionException
+ */
+ public function canGetGroups()
+ {
+ $expected = ['expected' => 'array'];
+ /** @var Configuration|MockObject $configurationMock */
+ $configurationMock = $this->getMockBuilder(Configuration::class)
+ ->onlyMethods(['getExportGroups'])
+ ->getMock();
+ $configurationMock->expects($this->atLeastOnce())->method('getExportGroups')->willReturn($expected);
+
+ $this->setValue($this->_oController, 'configuration', $configurationMock);
+
+ $this->assertSame(
+ $expected,
+ $this->callMethod(
+ $this->_oController,
+ 'getGroups'
+ )
+ );
+ }
+
+ /**
+ * @covers \D3\DataWizard\Application\Controller\Admin\d3ExportWizard::getGroupTasks()
+ * @test
+ * @throws ReflectionException
+ * @dataProvider canGetGroupTasksDataProvider
+ */
+ public function canGetGroupTasks($argument)
+ {
+ $expected = ['expected' => 'array'];
+ /** @var Configuration|MockObject $configurationMock */
+ $configurationMock = $this->getMockBuilder(Configuration::class)
+ ->onlyMethods(['getExportsByGroup'])
+ ->getMock();
+ $configurationMock->expects($this->atLeastOnce())->method('getExportsByGroup')->with($argument)->willReturn($expected);
+
+ $this->setValue($this->_oController, 'configuration', $configurationMock);
+
+ $this->assertSame(
+ $expected,
+ $this->callMethod(
+ $this->_oController,
+ 'getGroupTasks',
+ [$argument]
+ )
+ );
+ }
+
+ /**
+ * @return array
+ */
+ public function canGetGroupTasksDataProvider(): array
+ {
+ return [
+ ['test1'],
+ ['test2']
+ ];
+ }
+
+ /**
+ * @covers \D3\DataWizard\Application\Controller\Admin\d3ExportWizard::execute()
+ * @test
+ * @throws ReflectionException
+ * @dataProvider executePassDataProvider
+ */
+ public function executePass($blDebug)
+ {
+ /** @var Request|MockObject $requestMock */
+ $requestMock = $this->getMockBuilder(get_class(Registry::getRequest()))
+ ->onlyMethods(['getRequestEscapedParameter'])
+ ->getMock();
+ $requestMock->expects($this->any())->method('getRequestEscapedParameter')->willReturnCallback([$this, 'executePassRequestCallback']);
+ //OnConsecutiveCalls('testTaskId', 'CSV');
+ Registry::set(Request::class, $requestMock);
+
+ /** @var Config|MockObject $configMock */
+ $configMock = $this->getMockBuilder(Config::class)
+ ->onlyMethods(['getConfigParam'])
+ ->getMock();
+ $configMock->expects($this->atLeastOnce())->method('getConfigParam')->willReturnCallback(
+ function ($argName) use ($blDebug) {
+ switch ($argName) {
+ case 'd3datawizard_debug':
+ return $blDebug;
+ default:
+ return Registry::getConfig()->getConfigParam($argName);
+ }
+ }
+ );
+
+ /** @var d3ExportWizard|MockObject $controllerMock */
+ $controllerMock = $this->getMockBuilder(d3ExportWizard::class)
+ ->onlyMethods(['d3GetConfig'])
+ ->getMock();
+ $controllerMock->method('d3GetConfig')->willReturn($configMock);
+ $this->_oController = $controllerMock;
+
+ /** @var d3TestAction|MockObject $exportMock */
+ $exportMock = $this->getMockBuilder(d3TestExport::class)
+ ->onlyMethods([
+ 'getQuery',
+ 'run'
+ ])
+ ->getMock();
+ $exportMock->expects($this->atLeastOnce())->method('getQuery')->willReturn(['SELECT 1', ['1']]);
+ $exportMock->expects($this->exactly((int) !$blDebug))->method('run')->willReturn('');
+
+ /** @var Configuration|MockObject $configurationMock */
+ $configurationMock = $this->getMockBuilder(Configuration::class)
+ ->onlyMethods(['getExportById'])
+ ->disableOriginalConstructor()
+ ->getMock();
+ $configurationMock->expects($this->atLeastOnce())->method('getExportById')->with('testTaskId')->willReturn($exportMock);
+ $this->setValue($this->_oController, 'configuration', $configurationMock);
+
+ if ($blDebug) {
+ $this->expectException(DebugException::class);
+ }
+
+ $this->callMethod(
+ $this->_oController,
+ 'execute'
+ );
+ }
+
+ public function executePassRequestCallback($varName)
+ {
+ switch ($varName) {
+ case 'taskid':
+ return 'testTaskId';
+ case 'format':
+ return RendererBridge::FORMAT_CSV;
+ default:
+ return oxNew(Request::class)->getRequestEscapedParameter($varName);
+ }
+ }
+
+ /**
+ * @return array
+ */
+ public function executePassDataProvider(): array
+ {
+ return [
+ 'no debug' => [false],
+ 'debug' => [true],
+ ];
+ }
+}
\ No newline at end of file
diff --git a/tests/unit/Application/Model/ActionBaseTest.php b/tests/unit/Application/Model/ActionBaseTest.php
new file mode 100644
index 0000000..cedc94b
--- /dev/null
+++ b/tests/unit/Application/Model/ActionBaseTest.php
@@ -0,0 +1,316 @@
+
+ * @link https://www.oxidmodule.com
+ */
+
+declare(strict_types=1);
+
+namespace D3\DataWizard\tests\unit\Application\Model;
+
+use D3\DataWizard\Application\Model\Exceptions\TaskException;
+use D3\DataWizard\tests\tools\d3TestAction;
+use D3\ModCfg\Tests\unit\d3ModCfgUnitTestCase;
+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 PHPUnit\Framework\MockObject\MockObject;
+use ReflectionException;
+
+class ActionBaseTest extends d3ModCfgUnitTestCase
+{
+ /** @var d3TestAction */
+ protected $_oModel;
+
+ public function setUp() : void
+ {
+ parent::setUp();
+
+ $this->_oModel = oxNew(d3TestAction::class);
+ }
+
+ public function tearDown() : void
+ {
+ parent::tearDown();
+
+ unset($this->_oModel);
+ }
+
+ /**
+ * @covers \D3\DataWizard\Application\Model\ActionBase::getDescription
+ * @test
+ * @throws ReflectionException
+ */
+ public function canGetDescription()
+ {
+ $this->assertIsString(
+ $this->callMethod(
+ $this->_oModel,
+ 'getDescription'
+ )
+ );
+ }
+
+ /**
+ * @covers \D3\DataWizard\Application\Model\ActionBase::getButtonText
+ * @test
+ * @throws ReflectionException
+ */
+ public function canGetButtonText()
+ {
+ $this->assertIsString(
+ $this->callMethod(
+ $this->_oModel,
+ 'getButtonText'
+ )
+ );
+ }
+
+ /**
+ * @covers \D3\DataWizard\Application\Model\ActionBase::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()
+ {
+ return [
+ 'hasFormElements' => [['abc', 'def'], true],
+ 'hasNoFormElements' => [[], false],
+ ];
+ }
+
+ /**
+ * @covers \D3\DataWizard\Application\Model\ActionBase::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\ActionBase::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\ActionBase::run
+ * @test
+ * @throws ReflectionException
+ */
+ public function canRunWithoutFormElements()
+ {
+ $modelMock = $this->getMockBuilder(d3TestAction::class)
+ ->onlyMethods([
+ 'hasFormElements',
+ 'executeAction',
+ 'getQuery'
+ ])
+ ->getMock();
+ $modelMock->expects($this->atLeastOnce())->method('hasFormElements')->willReturn(false);
+ $modelMock->expects($this->atLeastOnce())->method('executeAction')->willReturn(1);
+ $modelMock->expects($this->atLeastOnce())->method('getQuery')->willReturn([]);
+ $this->_oModel = $modelMock;
+
+ $this->callMethod(
+ $this->_oModel,
+ 'run'
+ );
+ }
+
+ /**
+ * @covers \D3\DataWizard\Application\Model\ActionBase::run
+ * @test
+ * @throws ReflectionException
+ * @dataProvider canRunWithFormElementsDataProvider
+ */
+ public function canRunWithFormElements($elements, $blThrowException)
+ {
+ $expectedException = oxNew(StandardException::class);
+
+ $modelMock = $this->getMockBuilder(d3TestAction::class)
+ ->onlyMethods([
+ 'hasFormElements',
+ 'executeAction',
+ 'getQuery',
+ 'getFormElements'
+ ])
+ ->getMock();
+ $modelMock->expects($this->atLeastOnce())->method('hasFormElements')->willReturn(true);
+ $modelMock->expects($this->exactly((int) !$blThrowException))->method('executeAction')->willReturn(1);
+ $modelMock->expects($this->exactly((int) !$blThrowException))->method('getQuery')->willReturn([]);
+ $modelMock->expects($this->atLeastOnce())->method('getFormElements')->willReturn($elements);
+ $this->_oModel = $modelMock;
+
+ if ($blThrowException) {
+ $this->expectException(get_class($expectedException));
+ }
+
+ $this->callMethod(
+ $this->_oModel,
+ 'run'
+ );
+ }
+
+ /**
+ * @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\ActionBase::executeAction
+ * @test
+ * @throws ReflectionException
+ * @dataProvider canExecuteActionDataProvider
+ */
+ public function canExecuteAction($query, $throwsException)
+ {
+ /** @var Database|MockObject $dbMock */
+ $dbMock = $this->getMockBuilder(Database::class)
+ ->onlyMethods(['execute'])
+ ->getMock();
+ $dbMock->expects($this->exactly((int) !$throwsException))->method('execute')->willReturn(true);
+
+ /** @var d3TestAction|MockObject $modelMock */
+ $modelMock = $this->getMockBuilder(d3TestAction::class)
+ ->onlyMethods(['d3GetDb'])
+ ->getMock();
+ $modelMock->expects($this->exactly((int) !$throwsException))->method('d3GetDb')->willReturn($dbMock);
+
+ $this->_oModel = $modelMock;
+
+ try {
+ $this->callMethod(
+ $this->_oModel,
+ 'executeAction',
+ [[$query, ['parameters']]]
+ );
+ } catch (TaskException $e) {
+ if ($throwsException) {
+ $this->assertStringContainsString('ACTIONSELECT', $e->getMessage());
+ } else {
+ $this->assertStringContainsString('ACTIONRESULT', $e->getMessage());
+ }
+ }
+ }
+
+ /**
+ * @return array[]
+ */
+ public function canExecuteActionDataProvider(): array
+ {
+ return [
+ 'Select throws exception' => ['SELECT 1', true],
+ 'Update dont throws exception' => ['UPDATE 1', false],
+ ];
+ }
+
+ /**
+ * @covers \D3\DataWizard\Application\Model\ActionBase::d3GetDb
+ * @test
+ * @throws ReflectionException
+ */
+ public function canGetDb()
+ {
+ $this->assertInstanceOf(
+ Database::class,
+ $this->callMethod(
+ $this->_oModel,
+ 'd3GetDb'
+ )
+ );
+ }
+}
\ No newline at end of file
diff --git a/tests/unit/Application/Model/ConfigurationTest.php b/tests/unit/Application/Model/ConfigurationTest.php
new file mode 100644
index 0000000..1d8d163
--- /dev/null
+++ b/tests/unit/Application/Model/ConfigurationTest.php
@@ -0,0 +1,454 @@
+
+ * @link https://www.oxidmodule.com
+ */
+
+declare(strict_types=1);
+
+namespace D3\DataWizard\tests\unit\Application\Model;
+
+use D3\DataWizard\Application\Model\Configuration;
+use D3\DataWizard\Application\Model\Exceptions\DataWizardException;
+use D3\DataWizard\tests\tools\d3TestAction;
+use D3\DataWizard\tests\tools\d3TestExport;
+use D3\ModCfg\Tests\unit\d3ModCfgUnitTestCase;
+use PHPUnit\Framework\MockObject\MockObject;
+
+class ConfigurationTest extends d3ModCfgUnitTestCase
+{
+ /** @var Configuration */
+ protected $_oModel;
+
+ public function setUp() : void
+ {
+ parent::setUp();
+
+ $this->_oModel = oxNew(Configuration::class);
+ }
+
+ public function tearDown() : void
+ {
+ parent::tearDown();
+
+ unset($this->_oModel);
+ }
+
+ /**
+ * @covers \D3\DataWizard\Application\Model\Configuration::__construct
+ * @test
+ * @throws \ReflectionException
+ */
+ public function canConstruct()
+ {
+ /** @var Configuration|MockObject $modelMock */
+ $modelMock = $this->getMockBuilder(Configuration::class)
+ ->disableOriginalConstructor()
+ ->onlyMethods(['configure'])
+ ->getMock();
+ $modelMock->expects($this->once())->method('configure');
+ $this->_oModel = $modelMock;
+
+ $this->callMethod(
+ $this->_oModel,
+ '__construct'
+ );
+ }
+
+ /**
+ * @covers \D3\DataWizard\Application\Model\Configuration::configure()
+ * @test
+ * @throws \ReflectionException
+ */
+ public function canConfigure()
+ {
+ $this->assertEmpty(
+ $this->callMethod(
+ $this->_oModel,
+ 'configure'
+ )
+ );
+ }
+
+ /**
+ * @covers \D3\DataWizard\Application\Model\Configuration::registerAction
+ * @test
+ * @throws \ReflectionException
+ */
+ public function canRegisterAction()
+ {
+ $action = oxNew(d3TestAction::class);
+
+ $oldCount = count($this->getValue(
+ $this->_oModel,
+ 'actions'
+ ));
+
+ $this->callMethod(
+ $this->_oModel,
+ 'registerAction',
+ ['testGroup', $action]
+ );
+
+ $actions = $this->getValue(
+ $this->_oModel,
+ 'actions'
+ );
+
+ $newCount = count($actions);
+
+ $flattedActions = $this->array_flatten($actions);
+
+ $this->assertGreaterThan($oldCount, $newCount);
+ $this->assertContains($action, $flattedActions);
+ }
+
+ /**
+ * @covers \D3\DataWizard\Application\Model\Configuration::registerExport
+ * @test
+ * @throws \ReflectionException
+ */
+ public function canRegisterExport()
+ {
+ $export = oxNew(d3TestExport::class);
+
+ $oldCount = count($this->getValue(
+ $this->_oModel,
+ 'exports'
+ ));
+
+ $this->callMethod(
+ $this->_oModel,
+ 'registerExport',
+ ['testGroup', $export]
+ );
+
+ $exports = $this->getValue(
+ $this->_oModel,
+ 'exports'
+ );
+
+ $newCount = count($exports);
+
+ $flattedExports = $this->array_flatten($exports);
+
+ $this->assertGreaterThan($oldCount, $newCount);
+ $this->assertContains($export, $flattedExports);
+ }
+
+ /**
+ * @param $array
+ * @return array|false
+ */
+ public function array_flatten($array) {
+ if (!is_array($array)) {
+ return false;
+ }
+ $result = array();
+ foreach ($array as $key => $value) {
+ if (is_array($value)) {
+ $result = array_merge($result, $this->array_flatten($value));
+ }
+ else {
+ $result[$key] = $value;
+ }
+ }
+ return $result;
+ }
+
+ /**
+ * @covers \D3\DataWizard\Application\Model\Configuration::getGroupedActions()
+ * @test
+ * @throws \ReflectionException
+ */
+ public function canGetGroupedActions()
+ {
+ $actionList = ['abc', 'def'];
+
+ $this->setValue(
+ $this->_oModel,
+ 'actions',
+ $actionList
+ );
+
+ $this->assertSame(
+ $actionList,
+ $this->callMethod(
+ $this->_oModel,
+ 'getGroupedActions'
+ )
+ );
+ }
+
+ /**
+ * @covers \D3\DataWizard\Application\Model\Configuration::getGroupedExports()
+ * @test
+ * @throws \ReflectionException
+ */
+ public function canGetGroupedExports()
+ {
+ $exportList = ['abc', 'def'];
+
+ $this->setValue(
+ $this->_oModel,
+ 'exports',
+ $exportList
+ );
+
+ $this->assertSame(
+ $exportList,
+ $this->callMethod(
+ $this->_oModel,
+ 'getGroupedExports'
+ )
+ );
+ }
+
+ /**
+ * @covers \D3\DataWizard\Application\Model\Configuration::getActionGroups()
+ * @test
+ * @throws \ReflectionException
+ */
+ public function canGetActionGroups()
+ {
+ $actionList = ['abc' => '123', 'def' => '456'];
+
+ $this->setValue(
+ $this->_oModel,
+ 'actions',
+ $actionList
+ );
+
+ $this->assertSame(
+ ['abc', 'def'],
+ $this->callMethod(
+ $this->_oModel,
+ 'getActionGroups'
+ )
+ );
+ }
+
+ /**
+ * @covers \D3\DataWizard\Application\Model\Configuration::getExportGroups()
+ * @test
+ * @throws \ReflectionException
+ */
+ public function canGetExportGroups()
+ {
+ $exportList = ['abc' => '123', 'def' => '456'];
+
+ $this->setValue(
+ $this->_oModel,
+ 'exports',
+ $exportList
+ );
+
+ $this->assertSame(
+ ['abc', 'def'],
+ $this->callMethod(
+ $this->_oModel,
+ 'getExportGroups'
+ )
+ );
+ }
+
+ /**
+ * @covers \D3\DataWizard\Application\Model\Configuration::getActionsByGroup()
+ * @test
+ * @throws \ReflectionException
+ */
+ public function canGetActionsByGroup()
+ {
+ $actionList = ['abc' => '123', 'def' => '456'];
+
+ $this->setValue(
+ $this->_oModel,
+ 'actions',
+ $actionList
+ );
+
+ $this->assertSame(
+ '456',
+ $this->callMethod(
+ $this->_oModel,
+ 'getActionsByGroup',
+ ['def']
+ )
+ );
+ }
+
+ /**
+ * @covers \D3\DataWizard\Application\Model\Configuration::getExportsByGroup()
+ * @test
+ * @throws \ReflectionException
+ */
+ public function canGetExportsByGroup()
+ {
+ $exportList = ['abc' => '123', 'def' => '456'];
+
+ $this->setValue(
+ $this->_oModel,
+ 'exports',
+ $exportList
+ );
+
+ $this->assertSame(
+ '456',
+ $this->callMethod(
+ $this->_oModel,
+ 'getExportsByGroup',
+ ['def']
+ )
+ );
+ }
+
+ /**
+ * @covers \D3\DataWizard\Application\Model\Configuration::getAllActions()
+ * @test
+ * @throws \ReflectionException
+ */
+ public function canGetAllActions()
+ {
+ /** @var Configuration|MockObject $modelMock */
+ $modelMock = $this->getMockBuilder(Configuration::class)
+ ->onlyMethods([
+ 'getActionGroups',
+ 'getActionsByGroup'
+ ])
+ ->getMock();
+ $modelMock->expects($this->once())->method('getActionGroups')->willReturn(['123', '456']);
+ $modelMock->expects($this->exactly(2))->method('getActionsByGroup')->willReturnOnConsecutiveCalls(
+ ['123', '456'],
+ ['789', '012']
+ );
+
+ $this->_oModel = $modelMock;
+
+ $this->assertSame(
+ ['123','456', '789', '012'],
+ $this->callMethod(
+ $this->_oModel,
+ 'getAllActions'
+ )
+ );
+ }
+
+ /**
+ * @covers \D3\DataWizard\Application\Model\Configuration::getAllExports()
+ * @test
+ * @throws \ReflectionException
+ */
+ public function canGetAllExports()
+ {
+ /** @var Configuration|MockObject $modelMock */
+ $modelMock = $this->getMockBuilder(Configuration::class)
+ ->onlyMethods([
+ 'getExportGroups',
+ 'getExportsByGroup'
+ ])
+ ->getMock();
+ $modelMock->expects($this->once())->method('getExportGroups')->willReturn(['123', '456']);
+ $modelMock->expects($this->exactly(2))->method('getExportsByGroup')->willReturnOnConsecutiveCalls(
+ ['123', '456'],
+ ['789', '012']
+ );
+
+ $this->_oModel = $modelMock;
+
+ $this->assertSame(
+ ['123', '456', '789', '012'],
+ $this->callMethod(
+ $this->_oModel,
+ 'getAllExports'
+ )
+ );
+ }
+
+ /**
+ * @covers \D3\DataWizard\Application\Model\Configuration::getActionById()
+ * @test
+ * @throws \ReflectionException
+ * @dataProvider canGetActionByIdDataProvider
+ */
+ public function canGetActionById($id, $throwException)
+ {
+ $expected = oxNew(d3TestAction::class);
+
+ /** @var Configuration|MockObject $modelMock */
+ $modelMock = $this->getMockBuilder(Configuration::class)
+ ->onlyMethods(['getAllActions'])
+ ->getMock();
+ $modelMock->expects($this->once())->method('getAllActions')->willReturn(['123' => oxNew(d3TestAction::class), '456' => $expected]);
+ $this->_oModel = $modelMock;
+
+ if ($throwException) {
+ $this->expectException(DataWizardException::class);
+ }
+
+ $return = $this->callMethod(
+ $this->_oModel,
+ 'getActionById',
+ [$id]
+ );
+
+ if (!$throwException) {
+ $this->assertSame(
+ $expected,
+ $return
+ );
+ }
+ }
+
+ /**
+ * @covers \D3\DataWizard\Application\Model\Configuration::getExportById()
+ * @test
+ * @throws \ReflectionException
+ * @dataProvider canGetActionByIdDataProvider
+ */
+ public function canGetExportById($id, $throwException)
+ {
+ $expected = oxNew(d3TestExport::class);
+
+ /** @var Configuration|MockObject $modelMock */
+ $modelMock = $this->getMockBuilder(Configuration::class)
+ ->onlyMethods(['getAllExports'])
+ ->getMock();
+ $modelMock->expects($this->once())->method('getAllExports')->willReturn(['123' => oxNew(d3TestExport::class), '456' => $expected]);
+ $this->_oModel = $modelMock;
+
+ if ($throwException) {
+ $this->expectException(DataWizardException::class);
+ }
+
+ $return = $this->callMethod(
+ $this->_oModel,
+ 'getExportById',
+ [$id]
+ );
+
+ if (!$throwException) {
+ $this->assertSame(
+ $expected,
+ $return
+ );
+ }
+ }
+
+ /**
+ * @return array[]
+ */
+ public function canGetActionByIdDataProvider(): array
+ {
+ return [
+ 'unset id' => ['987', true],
+ 'set id' => ['456', false],
+ ];
+ }
+}
\ No newline at end of file
diff --git a/tests/unit/Application/Model/Exceptions/DebugExceptionTest.php b/tests/unit/Application/Model/Exceptions/DebugExceptionTest.php
new file mode 100644
index 0000000..779db2f
--- /dev/null
+++ b/tests/unit/Application/Model/Exceptions/DebugExceptionTest.php
@@ -0,0 +1,76 @@
+
+ * @link https://www.oxidmodule.com
+ */
+
+declare(strict_types=1);
+
+namespace D3\DataWizard\tests\unit\Application\Model\Exceptions;
+
+use D3\DataWizard\Application\Model\Exceptions\DebugException;
+use D3\ModCfg\Tests\unit\d3ModCfgUnitTestCase;
+use PHPUnit\Framework\MockObject\MockObject;
+
+class DebugExceptionTest extends d3ModCfgUnitTestCase
+{
+ /** @var DebugException */
+ protected $_oModel;
+
+ /**
+ * @covers \D3\DataWizard\Application\Model\Exceptions\DebugException::__construct
+ * @test
+ * @throws \ReflectionException
+ */
+ public function canConstruct()
+ {
+ $code = '500';
+
+ $exception = oxNew(\Exception::class);
+
+ /** @var DebugException|MockObject $modelMock */
+ $modelMock = $this->getMockBuilder(DebugException::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->_oModel = $modelMock;
+
+ $this->callMethod(
+ $this->_oModel,
+ '__construct',
+ ['testMessage', $code, $exception]
+ );
+
+ $this->assertStringContainsString(
+ 'DEBUG',
+ $this->callMethod(
+ $this->_oModel,
+ 'getMessage'
+ )
+ );
+
+ $this->assertEquals(
+ $code,
+ $this->callMethod(
+ $this->_oModel,
+ 'getCode'
+ )
+ );
+
+ $this->assertSame(
+ $exception,
+ $this->callMethod(
+ $this->_oModel,
+ 'getPrevious'
+ )
+ );
+ }
+
+}
\ No newline at end of file
diff --git a/tests/unit/Application/Model/Exceptions/ExportFileExceptionTest.php b/tests/unit/Application/Model/Exceptions/ExportFileExceptionTest.php
new file mode 100644
index 0000000..be6d83e
--- /dev/null
+++ b/tests/unit/Application/Model/Exceptions/ExportFileExceptionTest.php
@@ -0,0 +1,76 @@
+
+ * @link https://www.oxidmodule.com
+ */
+
+declare(strict_types=1);
+
+namespace D3\DataWizard\tests\unit\Application\Model\Exceptions;
+
+use D3\DataWizard\Application\Model\Exceptions\ExportFileException;
+use D3\ModCfg\Tests\unit\d3ModCfgUnitTestCase;
+use PHPUnit\Framework\MockObject\MockObject;
+
+class ExportFileExceptionTest extends d3ModCfgUnitTestCase
+{
+ /** @var ExportFileException */
+ protected $_oModel;
+
+ /**
+ * @covers \D3\DataWizard\Application\Model\Exceptions\ExportFileException::__construct
+ * @test
+ * @throws \ReflectionException
+ */
+ public function canConstruct()
+ {
+ $code = '500';
+
+ $exception = oxNew(\Exception::class);
+
+ /** @var ExportFileException|MockObject $modelMock */
+ $modelMock = $this->getMockBuilder(ExportFileException::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->_oModel = $modelMock;
+
+ $this->callMethod(
+ $this->_oModel,
+ '__construct',
+ ['testMessage', $code, $exception]
+ );
+
+ $this->assertStringContainsString(
+ 'EXPORTFILEERROR',
+ $this->callMethod(
+ $this->_oModel,
+ 'getMessage'
+ )
+ );
+
+ $this->assertEquals(
+ $code,
+ $this->callMethod(
+ $this->_oModel,
+ 'getCode'
+ )
+ );
+
+ $this->assertSame(
+ $exception,
+ $this->callMethod(
+ $this->_oModel,
+ 'getPrevious'
+ )
+ );
+ }
+
+}
\ No newline at end of file
diff --git a/tests/unit/Application/Model/Exceptions/InputUnvalidExceptionTest.php b/tests/unit/Application/Model/Exceptions/InputUnvalidExceptionTest.php
new file mode 100644
index 0000000..2dfe869
--- /dev/null
+++ b/tests/unit/Application/Model/Exceptions/InputUnvalidExceptionTest.php
@@ -0,0 +1,96 @@
+
+ * @link https://www.oxidmodule.com
+ */
+
+declare(strict_types=1);
+
+namespace D3\DataWizard\tests\unit\Application\Model\Exceptions;
+
+use D3\DataWizard\Application\Model\Exceptions\InputUnvalidException;
+use D3\DataWizard\Application\Model\ExportBase;
+use D3\DataWizard\tests\tools\d3TestExport;
+use D3\ModCfg\Tests\unit\d3ModCfgUnitTestCase;
+use FormManager\Inputs\Number;
+use PHPUnit\Framework\MockObject\MockObject;
+
+class InputUnvalidExceptionTest extends d3ModCfgUnitTestCase
+{
+ /** @var InputUnvalidException */
+ protected $_oModel;
+
+ /**
+ * @covers \D3\DataWizard\Application\Model\Exceptions\InputUnvalidException::__construct
+ * @test
+ * @throws \ReflectionException
+ */
+ public function canConstruct()
+ {
+ $code = '500';
+
+ $exception = oxNew(\Exception::class);
+
+ /** @var Number $invalidField */
+ $invalidField = new Number(null, [
+ 'required' => true,
+ 'min' => 1,
+ 'max' => 10,
+ 'step' => 5,
+ ]);
+ $invalidField
+ ->setValue(20)
+ ->setErrorMessages(['errorMsgs']);
+
+ /** @var ExportBase|MockObject $taskMock */
+ $taskMock = $this->getMockBuilder(d3TestExport::class)
+ ->onlyMethods(['getTitle'])
+ ->getMock();
+ $taskMock->expects($this->atLeastOnce())->method('getTitle')->willReturn('testTitle');
+
+ /** @var InputUnvalidException|MockObject $modelMock */
+ $modelMock = $this->getMockBuilder(InputUnvalidException::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->_oModel = $modelMock;
+
+ $this->callMethod(
+ $this->_oModel,
+ '__construct',
+ [$taskMock, $invalidField, $code, $exception]
+ );
+
+ $this->assertRegExp(
+ '/^testTitle\s-\s*->\s.*\sless\s/m',
+ $this->callMethod(
+ $this->_oModel,
+ 'getMessage'
+ )
+ );
+
+ $this->assertEquals(
+ $code,
+ $this->callMethod(
+ $this->_oModel,
+ 'getCode'
+ )
+ );
+
+ $this->assertSame(
+ $exception,
+ $this->callMethod(
+ $this->_oModel,
+ 'getPrevious'
+ )
+ );
+ }
+
+}
\ No newline at end of file
diff --git a/tests/unit/Application/Model/Exceptions/NoSuitableRendererExceptionTest.php b/tests/unit/Application/Model/Exceptions/NoSuitableRendererExceptionTest.php
new file mode 100644
index 0000000..49e34b0
--- /dev/null
+++ b/tests/unit/Application/Model/Exceptions/NoSuitableRendererExceptionTest.php
@@ -0,0 +1,76 @@
+
+ * @link https://www.oxidmodule.com
+ */
+
+declare(strict_types=1);
+
+namespace D3\DataWizard\tests\unit\Application\Model\Exceptions;
+
+use D3\DataWizard\Application\Model\Exceptions\NoSuitableRendererException;
+use D3\ModCfg\Tests\unit\d3ModCfgUnitTestCase;
+use PHPUnit\Framework\MockObject\MockObject;
+
+class NoSuitableRendererExceptionTest extends d3ModCfgUnitTestCase
+{
+ /** @var NoSuitableRendererException */
+ protected $_oModel;
+
+ /**
+ * @covers \D3\DataWizard\Application\Model\Exceptions\NoSuitableRendererException::__construct
+ * @test
+ * @throws \ReflectionException
+ */
+ public function canConstruct()
+ {
+ $code = '500';
+
+ $exception = oxNew(\Exception::class);
+
+ /** @var NoSuitableRendererException|MockObject $modelMock */
+ $modelMock = $this->getMockBuilder(NoSuitableRendererException::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->_oModel = $modelMock;
+
+ $this->callMethod(
+ $this->_oModel,
+ '__construct',
+ ['testMessage', $code, $exception]
+ );
+
+ $this->assertStringContainsString(
+ 'NOSUITABLERENDERER',
+ $this->callMethod(
+ $this->_oModel,
+ 'getMessage'
+ )
+ );
+
+ $this->assertEquals(
+ $code,
+ $this->callMethod(
+ $this->_oModel,
+ 'getCode'
+ )
+ );
+
+ $this->assertSame(
+ $exception,
+ $this->callMethod(
+ $this->_oModel,
+ 'getPrevious'
+ )
+ );
+ }
+
+}
\ No newline at end of file
diff --git a/tests/unit/Application/Model/Exceptions/TaskExceptionTest.php b/tests/unit/Application/Model/Exceptions/TaskExceptionTest.php
new file mode 100644
index 0000000..f9d5cd4
--- /dev/null
+++ b/tests/unit/Application/Model/Exceptions/TaskExceptionTest.php
@@ -0,0 +1,84 @@
+
+ * @link https://www.oxidmodule.com
+ */
+
+declare(strict_types=1);
+
+namespace D3\DataWizard\tests\unit\Application\Model\Exceptions;
+
+use D3\DataWizard\Application\Model\Exceptions\TaskException;
+use D3\DataWizard\Application\Model\ExportBase;
+use D3\DataWizard\tests\tools\d3TestExport;
+use D3\ModCfg\Tests\unit\d3ModCfgUnitTestCase;
+use PHPUnit\Framework\MockObject\MockObject;
+
+class TaskExceptionTest extends d3ModCfgUnitTestCase
+{
+ /** @var TaskException */
+ protected $_oModel;
+
+ /**
+ * @covers \D3\DataWizard\Application\Model\Exceptions\TaskException::__construct
+ * @test
+ * @throws \ReflectionException
+ */
+ public function canConstruct()
+ {
+ $code = '500';
+
+ $exception = oxNew(\Exception::class);
+
+ /** @var ExportBase|MockObject $taskMock */
+ $taskMock = $this->getMockBuilder(d3TestExport::class)
+ ->onlyMethods(['getTitle'])
+ ->getMock();
+ $taskMock->expects($this->atLeastOnce())->method('getTitle')->willReturn('testTitle');
+
+ /** @var TaskException|MockObject $modelMock */
+ $modelMock = $this->getMockBuilder(TaskException::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->_oModel = $modelMock;
+
+ $this->callMethod(
+ $this->_oModel,
+ '__construct',
+ [$taskMock, 'testMessage', $code, $exception]
+ );
+
+ $this->assertSame(
+ 'testTitle - testMessage',
+ $this->callMethod(
+ $this->_oModel,
+ 'getMessage'
+ )
+ );
+
+ $this->assertEquals(
+ $code,
+ $this->callMethod(
+ $this->_oModel,
+ 'getCode'
+ )
+ );
+
+ $this->assertSame(
+ $exception,
+ $this->callMethod(
+ $this->_oModel,
+ 'getPrevious'
+ )
+ );
+ }
+
+}
\ No newline at end of file
diff --git a/tests/unit/Application/Model/ExportBaseTest.php b/tests/unit/Application/Model/ExportBaseTest.php
new file mode 100644
index 0000000..e486956
--- /dev/null
+++ b/tests/unit/Application/Model/ExportBaseTest.php
@@ -0,0 +1,607 @@
+
+ * @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 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 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()
+ {
+ 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([
+ 'getQuery',
+ 'getExportData',
+ 'renderContent',
+ 'getFileSystem',
+ 'getExportFileName'
+ ])
+ ->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');
+ $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::d3GetDb
+ * @test
+ * @throws ReflectionException
+ */
+ public function canGetDb()
+ {
+ $this->assertInstanceOf(
+ Database::class,
+ $this->callMethod(
+ $this->_oModel,
+ 'd3GetDb'
+ )
+ );
+ }
+
+ /**
+ * @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->assertRegExp(
+ '/^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 Database|MockObject $dbMock */
+ $dbMock = $this->getMockBuilder(Database::class)
+ ->onlyMethods(['getAll'])
+ ->getMock();
+ $dbMock->expects($this->exactly((int) !$throwsException))->method('getAll')->willReturn($dbResult);
+
+ /** @var d3TestExport|MockObject $modelMock */
+ $modelMock = $this->getMockBuilder(d3TestExport::class)
+ ->onlyMethods([
+ 'd3GetDb'
+ ])
+ ->getMock();
+ $modelMock->expects($this->exactly((int) !$throwsException))->method('d3GetDb')->willReturn($dbMock);
+
+ $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']]],
+ ];
+ }
+}
\ No newline at end of file
diff --git a/tests/unit/Application/Model/ExportRenderer/CsvTest.php b/tests/unit/Application/Model/ExportRenderer/CsvTest.php
new file mode 100644
index 0000000..2968a1b
--- /dev/null
+++ b/tests/unit/Application/Model/ExportRenderer/CsvTest.php
@@ -0,0 +1,180 @@
+
+ * @link https://www.oxidmodule.com
+ */
+
+declare(strict_types=1);
+
+namespace D3\DataWizard\tests\unit\Application\Model\ExportRenderer;
+
+use D3\DataWizard\Application\Model\Exceptions\RenderException;
+use D3\DataWizard\Application\Model\ExportRenderer\Csv;
+use League\Csv\Exception;
+use League\Csv\Writer;
+use OxidEsales\Eshop\Core\Config;
+use OxidEsales\Eshop\Core\Registry;
+use PHPUnit\Framework\MockObject\MockObject;
+
+class CsvTest extends ExportRendererTest
+{
+ /** @var Csv */
+ protected $_oModel;
+
+ public function setUp() : void
+ {
+ parent::setUp();
+
+ $this->_oModel = oxNew(Csv::class);
+ }
+
+ /**
+ * @covers \D3\DataWizard\Application\Model\ExportRenderer\Csv::getContent
+ * @test
+ * @throws \ReflectionException
+ * @dataProvider canGetContentDataProvider
+ */
+ public function canGetContent($blThrowException)
+ {
+ $expected = 'expectedReturn';
+ $fieldList = ['field1', 'field2'];
+ $valueList = ['value1', 'value2'];
+
+ /** @var Writer|MockObject $csvMock */
+ $csvMockBuilder = $this->getMockBuilder(Writer::class);
+ $csvMockBuilder->disableOriginalConstructor();
+ $onlyMethods = ['insertOne', 'insertAll'];
+ if (method_exists($csvMockBuilder->getMock(), 'getContent')) {
+ $onlyMethods[] = 'getContent';
+ } else {
+ $csvMockBuilder->addMethods(['getContent']);
+ }
+ $csvMockBuilder->onlyMethods($onlyMethods);
+ $csvMock = $csvMockBuilder->getMock();
+
+ if ($blThrowException) {
+ $csvMock->expects($this->atLeastOnce())->method('getContent')->willThrowException(oxNew(Exception::class));
+ $this->expectException(RenderException::class);
+ } else {
+ $csvMock->expects($this->atLeastOnce())->method('getContent')->willReturn($expected);
+ }
+ $csvMock->expects($this->atLeastOnce())->method('insertOne')->with($fieldList)->willReturn(1);
+ $csvMock->expects($this->atLeastOnce())->method('insertAll')->with($valueList)->willReturn(1);
+
+ /** @var Csv|MockObject $modelMock */
+ $modelMock = $this->getMockBuilder(Csv::class)
+ ->onlyMethods(['getCsv'])
+ ->getMock();
+ $modelMock->expects($this->atLeastOnce())->method('getCsv')->willReturn($csvMock);
+ $this->_oModel = $modelMock;
+
+ $this->assertSame(
+ $expected,
+ $this->callMethod(
+ $this->_oModel,
+ 'getContent',
+ [$valueList, $fieldList]
+ )
+ );
+ }
+
+ /**
+ * @return array
+ */
+ public function canGetContentDataProvider(): array
+ {
+ return [
+ 'exception' => [true],
+ 'no exception' => [false]
+ ];
+ }
+
+ /**
+ * @covers \D3\DataWizard\Application\Model\ExportRenderer\Csv::getCsv
+ * @test
+ * @throws \ReflectionException
+ */
+ public function canGetCsv()
+ {
+ $this->assertInstanceOf(
+ Writer::class,
+ $this->callMethod(
+ $this->_oModel,
+ 'getCsv'
+ )
+ );
+ }
+
+ /**
+ * @covers \D3\DataWizard\Application\Model\ExportRenderer\Csv::getCsv
+ * @test
+ * @throws \ReflectionException
+ */
+ public function canGetCsvNoSettings()
+ {
+ /** @var Config|MockObject $configMock */
+ $configMock = $this->getMockBuilder(Config::class)
+ ->onlyMethods(['getConfigParam'])
+ ->getMock();
+ $configMock->expects($this->atLeastOnce())->method('getConfigParam')->willReturnCallback(
+ function ($argName) {
+ switch ($argName) {
+ case 'sGiCsvFieldEncloser':
+ case 'sCSVSign':
+ return false;
+ default:
+ return Registry::getConfig()->getConfigParam($argName);
+ }
+ }
+ );
+
+ $modelMock = $this->getMockBuilder(Csv::class)
+ ->onlyMethods(['d3GetConfig'])
+ ->getMock();
+ $modelMock->method('d3GetConfig')->willReturn($configMock);
+ $this->_oModel = $modelMock;
+
+ $csv = $this->callMethod(
+ $this->_oModel,
+ 'getCsv'
+ );
+
+ $this->assertInstanceOf(
+ Writer::class,
+ $csv
+ );
+
+ $this->assertSame(
+ '"',
+ $csv->getEnclosure()
+ );
+
+ $this->assertSame(
+ ';',
+ $csv->getDelimiter()
+ );
+ }
+
+ /**
+ * @covers \D3\DataWizard\Application\Model\ExportRenderer\Csv::d3GetConfig
+ * @test
+ * @throws \ReflectionException
+ */
+ public function canGetConfig()
+ {
+ $this->assertInstanceOf(
+ Config::class,
+ $this->callMethod(
+ $this->_oModel,
+ 'd3GetConfig'
+ )
+ );
+ }
+}
\ No newline at end of file
diff --git a/tests/unit/Application/Model/ExportRenderer/ExportRendererTest.php b/tests/unit/Application/Model/ExportRenderer/ExportRendererTest.php
new file mode 100644
index 0000000..f89dede
--- /dev/null
+++ b/tests/unit/Application/Model/ExportRenderer/ExportRendererTest.php
@@ -0,0 +1,65 @@
+
+ * @link https://www.oxidmodule.com
+ */
+
+namespace D3\DataWizard\tests\unit\Application\Model\ExportRenderer;
+
+use D3\DataWizard\Application\Model\ExportRenderer\RendererInterface;
+use D3\ModCfg\Tests\unit\d3ModCfgUnitTestCase;
+
+abstract class ExportRendererTest extends d3ModCfgUnitTestCase
+{
+ /** @var RendererInterface */
+ protected $_oModel;
+
+ public function tearDown() : void
+ {
+ parent::tearDown();
+
+ unset($this->_oModel);
+ }
+
+ /**
+ * @covers \D3\DataWizard\Application\Model\ExportRenderer\Csv::getFileExtension
+ * @covers \D3\DataWizard\Application\Model\ExportRenderer\Json::getFileExtension
+ * @covers \D3\DataWizard\Application\Model\ExportRenderer\Pretty::getFileExtension
+ * @test
+ * @throws \ReflectionException
+ */
+ public function canGetFileExtension()
+ {
+ $this->assertRegExp(
+ "/^[a-z0-9._-]*$/i",
+ $this->callMethod(
+ $this->_oModel,
+ 'getFileExtension'
+ )
+ );
+ }
+
+ /**
+ * @covers \D3\DataWizard\Application\Model\ExportRenderer\Csv::getTitleTranslationId
+ * @covers \D3\DataWizard\Application\Model\ExportRenderer\Json::getTitleTranslationId
+ * @covers \D3\DataWizard\Application\Model\ExportRenderer\Pretty::getTitleTranslationId
+ * @test
+ * @throws \ReflectionException
+ */
+ public function canGetTitleTranslationId()
+ {
+ $this->assertIsString(
+ $this->callMethod(
+ $this->_oModel,
+ 'getTitleTranslationId'
+ )
+ );
+ }
+}
\ No newline at end of file
diff --git a/tests/unit/Application/Model/ExportRenderer/JsonTest.php b/tests/unit/Application/Model/ExportRenderer/JsonTest.php
new file mode 100644
index 0000000..413aa80
--- /dev/null
+++ b/tests/unit/Application/Model/ExportRenderer/JsonTest.php
@@ -0,0 +1,66 @@
+
+ * @link https://www.oxidmodule.com
+ */
+
+declare(strict_types=1);
+
+namespace D3\DataWizard\tests\unit\Application\Model\ExportRenderer;
+
+use D3\DataWizard\Application\Model\Exceptions\RenderException;
+use D3\DataWizard\Application\Model\ExportRenderer\Json;
+
+class JsonTest extends ExportRendererTest
+{
+ /** @var Json */
+ protected $_oModel;
+
+ public function setUp() : void
+ {
+ parent::setUp();
+
+ $this->_oModel = oxNew(Json::class);
+ }
+
+ /**
+ * @covers \D3\DataWizard\Application\Model\ExportRenderer\Json::getContent
+ * @test
+ * @throws \ReflectionException
+ * @dataProvider canGetContentDataProvider
+ */
+ public function canGetContent($valueList, $expectException)
+ {
+ $fieldList = ['field1', 'field2'];
+
+ if ($expectException) {
+ $this->expectException(RenderException::class);
+ }
+
+ $this->assertJson(
+ $this->callMethod(
+ $this->_oModel,
+ 'getContent',
+ [$valueList, $fieldList]
+ )
+ );
+ }
+
+ /**
+ * @return \string[][]
+ */
+ public function canGetContentDataProvider(): array
+ {
+ return [
+ 'valid' => [['value1', 'value2'], false],
+ 'invalid' => [["text" => "\xB1\x31"], true] // malformed UTF8 chars
+ ];
+ }
+}
\ No newline at end of file
diff --git a/tests/unit/Application/Model/ExportRenderer/PrettyTest.php b/tests/unit/Application/Model/ExportRenderer/PrettyTest.php
new file mode 100644
index 0000000..481d9ec
--- /dev/null
+++ b/tests/unit/Application/Model/ExportRenderer/PrettyTest.php
@@ -0,0 +1,85 @@
+
+ * @link https://www.oxidmodule.com
+ */
+
+declare(strict_types=1);
+
+namespace D3\DataWizard\tests\unit\Application\Model\ExportRenderer;
+
+use D3\DataWizard\Application\Model\ExportRenderer\Pretty;
+use MathieuViossat\Util\ArrayToTextTable;
+use PHPUnit\Framework\MockObject\MockObject;
+
+class PrettyTest extends ExportRendererTest
+{
+ /** @var Pretty */
+ protected $_oModel;
+
+ public function setUp() : void
+ {
+ parent::setUp();
+
+ $this->_oModel = oxNew(Pretty::class);
+ }
+
+ /**
+ * @covers \D3\DataWizard\Application\Model\ExportRenderer\Pretty::getContent
+ * @test
+ * @throws \ReflectionException
+ */
+ public function canGetContent()
+ {
+ $expected = 'expectedReturn';
+ $fieldList = ['field1', 'field2'];
+ $valueList = ['value1', 'value2'];
+
+ /** @var ArrayToTextTable|MockObject $csvMock */
+ $arrayToTextTableMock = $this->getMockBuilder(ArrayToTextTable::class)
+ ->disableOriginalConstructor()
+ ->onlyMethods(['getTable'])
+ ->getMock();
+ $arrayToTextTableMock->expects($this->atLeastOnce())->method('getTable')->willReturn($expected);
+
+ /** @var Pretty|MockObject $modelMock */
+ $modelMock = $this->getMockBuilder(Pretty::class)
+ ->onlyMethods(['getArrayToTextTableInstance'])
+ ->getMock();
+ $modelMock->expects($this->atLeastOnce())->method('getArrayToTextTableInstance')->willReturn($arrayToTextTableMock);
+ $this->_oModel = $modelMock;
+
+ $this->assertSame(
+ $expected,
+ $this->callMethod(
+ $this->_oModel,
+ 'getContent',
+ [$valueList, $fieldList]
+ )
+ );
+ }
+
+ /**
+ * @covers \D3\DataWizard\Application\Model\ExportRenderer\Pretty::getArrayToTextTableInstance
+ * @test
+ * @throws \ReflectionException
+ */
+ public function canGetArrayToTextTableInstance()
+ {
+ $this->assertInstanceOf(
+ ArrayToTextTable::class,
+ $this->callMethod(
+ $this->_oModel,
+ 'getArrayToTextTableInstance',
+ [['field1', 'field2']]
+ )
+ );
+ }
+}
\ No newline at end of file
diff --git a/tests/unit/Application/Model/ExportRenderer/RendererBridgeTest.php b/tests/unit/Application/Model/ExportRenderer/RendererBridgeTest.php
new file mode 100644
index 0000000..c7c5c07
--- /dev/null
+++ b/tests/unit/Application/Model/ExportRenderer/RendererBridgeTest.php
@@ -0,0 +1,151 @@
+
+ * @link https://www.oxidmodule.com
+ */
+
+declare(strict_types=1);
+
+namespace D3\DataWizard\tests\unit\Application\Model\ExportRenderer;
+
+use D3\DataWizard\Application\Model\Exceptions\NoSuitableRendererException;
+use D3\DataWizard\Application\Model\ExportRenderer\Csv;
+use D3\DataWizard\Application\Model\ExportRenderer\Json;
+use D3\DataWizard\Application\Model\ExportRenderer\Pretty;
+use D3\DataWizard\Application\Model\ExportRenderer\RendererBridge;
+use D3\DataWizard\Application\Model\ExportRenderer\RendererInterface;
+use D3\ModCfg\Tests\unit\d3ModCfgUnitTestCase;
+use PHPUnit\Framework\MockObject\MockObject;
+
+class RendererBridgeTest extends d3ModCfgUnitTestCase
+{
+ /** @var RendererBridge */
+ protected $_oModel;
+
+ public function setUp() : void
+ {
+ parent::setUp();
+
+ $this->_oModel = oxNew(RendererBridge::class);
+ }
+
+ public function tearDown(): void
+ {
+ parent::tearDown();
+
+ unset($this->_oModel);
+ }
+
+ /**
+ * @covers \D3\DataWizard\Application\Model\ExportRenderer\RendererBridge::getRendererList
+ * @test
+ * @throws \ReflectionException
+ */
+ public function canGetRendererList()
+ {
+ $list = $this->callMethod(
+ $this->_oModel,
+ 'getRendererList'
+ );
+
+ $this->assertIsArray($list);
+ $this->assertTrue((bool) count($list));
+ }
+
+ /**
+ * @covers \D3\DataWizard\Application\Model\ExportRenderer\RendererBridge::getTranslatedRendererIdList
+ * @test
+ * @throws \ReflectionException
+ */
+ public function canGetTranslatedRendererIdList()
+ {
+ $utlist = $this->callMethod(
+ $this->_oModel,
+ 'getRendererList'
+ );
+
+ $list = $this->callMethod(
+ $this->_oModel,
+ 'getTranslatedRendererIdList'
+ );
+
+ $this->assertIsArray($list);
+ $this->assertTrue((bool) count($list));
+ $this->assertSame(count($utlist), count($list));
+ }
+
+ /**
+ * @covers \D3\DataWizard\Application\Model\ExportRenderer\RendererBridge::translateRendererId
+ * @test
+ * @throws \ReflectionException
+ */
+ public function canTranslateRendererId()
+ {
+ $expected = "expectedTranslation";
+
+ /** @var RendererInterface|MockObject $renderMock */
+ $renderMock = $this->getMockBuilder(Pretty::class)
+ ->onlyMethods(['getTitleTranslationId'])
+ ->getMock();
+ $renderMock->expects($this->atLeastOnce())->method('getTitleTranslationId')->willReturn($expected);
+
+ $this->callMethod(
+ $this->_oModel,
+ 'translateRendererId',
+ [$renderMock]
+ );
+ }
+
+ /**
+ * @covers \D3\DataWizard\Application\Model\ExportRenderer\RendererBridge::getRenderer
+ * @test
+ * @param $format
+ * @param $blThrowException
+ * @throws \ReflectionException
+ * @dataProvider canGetRendererDataProvider
+ */
+ public function canGetRenderer($format, $blThrowException)
+ {
+ /** @var RendererBridge|MockObject $modelMock */
+ $modelMock = $this->getMockBuilder(RendererBridge::class)
+ ->onlyMethods(['getRendererList'])
+ ->getMock();
+ $modelMock->expects($this->atLeastOnce())->method('getRendererList')->willReturn(
+ [
+ 'CSV' => $this->getMockBuilder(Csv::class)->getMock(),
+ 'Pretty' => $this->getMockBuilder(Pretty::class)->getMock(),
+ 'JSON' => $this->getMockBuilder(Json::class)->getMock()
+ ]
+ );
+
+ $this->_oModel = $modelMock;
+
+ if ($blThrowException) {
+ $this->expectException(NoSuitableRendererException::class);
+ }
+
+ $this->callMethod(
+ $this->_oModel,
+ 'getRenderer',
+ [$format]
+ );
+ }
+
+ /**
+ * @return array
+ */
+ public function canGetRendererDataProvider(): array
+ {
+ return [
+ 'existing renderer'=> [RendererBridge::FORMAT_JSON, false],
+ 'unknown renderer'=> ['unknownRenderer', true]
+ ];
+ }
+}
\ No newline at end of file