diff --git a/tests/.gitignore b/tests/.gitignore
new file mode 100644
index 0000000..165765a
--- /dev/null
+++ b/tests/.gitignore
@@ -0,0 +1 @@
+.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/reports/logfile.xml b/tests/reports/logfile.xml
new file mode 100644
index 0000000..c7f9b6c
--- /dev/null
+++ b/tests/reports/logfile.xml
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/tools/d3TestAction.php b/tests/tools/d3TestAction.php
new file mode 100644
index 0000000..18fd56f
--- /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\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;
+
+ public function setUp() : void
+ {
+ parent::setUp();
+
+ $this->_oController = oxNew(d3ActionWizard::class);
+ }
+
+ /**
+ * @covers 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 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 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->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],
+ ];
+ }
+}
\ 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..7be5e8e
--- /dev/null
+++ b/tests/unit/Application/Controller/Admin/d3AdminControllerTest.php
@@ -0,0 +1,238 @@
+
+ * @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;
+
+ 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 d3ActionWizard::runTask()
+ * @test
+ * @throws ReflectionException
+ */
+ public function runTaskPass()
+ {
+ /** @var d3ActionWizard|MockObject $controllerMock */
+ $controllerMock = $this->getMockBuilder(d3ActionWizard::class)
+ ->onlyMethods(['execute'])
+ ->getMock();
+ $controllerMock->expects($this->once())->method('execute')->willReturn(true);
+
+ $this->_oController = $controllerMock;
+
+ $this->callMethod(
+ $this->_oController,
+ 'runTask'
+ );
+ }
+
+ /**
+ * @covers d3ActionWizard::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|MockObject $controllerMock */
+ $controllerMock = $this->getMockBuilder(d3ActionWizard::class)
+ ->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 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->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 d3ActionWizard::getUserMessages()
+ * @test
+ * @throws ReflectionException
+ */
+ public function canGetUserMessages()
+ {
+ $this->assertNull(
+ $this->callMethod(
+ $this->_oController,
+ 'getUserMessages'
+ )
+ );
+ }
+
+ /**
+ * @covers d3ActionWizard::getHelpURL()
+ * @test
+ * @throws ReflectionException
+ */
+ public function canGetHelpUrl()
+ {
+ $this->assertNull(
+ $this->callMethod(
+ $this->_oController,
+ 'getHelpURL'
+ )
+ );
+ }
+}
\ 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..678ef39
--- /dev/null
+++ b/tests/unit/Application/Controller/Admin/d3ExportWizardTest.php
@@ -0,0 +1,168 @@
+
+ * @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\DebugException;
+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;
+
+ public function setUp() : void
+ {
+ parent::setUp();
+
+ $this->_oController = oxNew(d3ExportWizard::class);
+ }
+
+ /**
+ * @covers d3ActionWizard::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 d3ActionWizard::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 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->exactly($blDebug ? 1 : 2))->method('getRequestEscapedParameter')->withConsecutive(
+ ['taskid'], ['format']
+ )->willReturnOnConsecutiveCalls('testTaskId', 'CSV');
+ Registry::set(Request::class, $requestMock);
+
+ /** @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);
+
+ /** @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],
+ ];
+ }
+}
\ No newline at end of file