Files
kupshop/tests/functional/DatabaseTestCase.php
2025-08-02 16:30:27 +02:00

326 lines
9.2 KiB
PHP

<?php
use KupShop\DevelopmentBundle\Util\Tests\ContainerAwareTestTrait;
use KupShop\KupShopBundle\Config;
use KupShop\KupShopBundle\Context\ContextManager;
use KupShop\KupShopBundle\Util\Compat\ServiceContainer;
use KupShop\KupShopBundle\Util\Contexts;
use Symfony\Component\HttpFoundation\Request;
class DatabaseTestCase extends \PHPUnit\DbUnit\TestCase
{
use ContainerAwareTestTrait;
use DatabaseCommunication;
private static $cfg;
private static $dbcfg;
private static $txt_str;
private $transactionActivated = false;
private $contextManager;
protected function setUp(): void
{
$this->getTestResultObject()->stopOnError(true);
$this->getTestResultObject()->stopOnFailure(true);
$this->restoreDefaultConfig();
$this->restoreDefaultSettings();
$this->restoreDefaultCtrl();
$this->restoreDefaultLanguage();
// Clear caches
$this->clearCaches();
// Clear cache by generating new BUILD_ID for each test
static $iteration = 0;
$iteration++;
$db = TEST_DB_NAME;
putenv("BUILD_ID={$db}_{$iteration}");
$this->suspendLogging(true);
$this->assertSame(0, sqlGetConnection()->getTransactionNestingLevel(), 'The test itself must not be in a transaction.');
sqlStartTransaction();
$this->transactionActivated = true;
$this->setTestDefaults();
$this->suspendLogging(false);
$this->updateModules();
parent::setUp();
// todo find how to restore previous values, not force false. This unfortunately overrides respective cli flags
$this->getTestResultObject()->stopOnError(false);
$this->getTestResultObject()->stopOnFailure(false);
}
protected function tearDown(): void
{
parent::tearDown();
$this->suspendLogging(true);
$this->assertSameTransactionLevel();
sqlRollbackTransaction();
$this->assertNoChangesLeftInDatabase();
$this->suspendLogging(false);
$this->tearDownContainer();
// Reverting sql_mode
// sqlQuery("SET sql_mode = 'NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION'");
}
public function addModule($module, $submodule = null, $restartContainer = false)
{
$cfg = \KupShop\KupShopBundle\Config::get();
if ($submodule) {
if (is_array($cfg['Modules'][$module])) {
$cfg['Modules'][$module][$submodule] = true;
} else {
$cfg['Modules'][$module] = [$submodule => true];
}
} else {
$cfg['Modules'][$module] = true;
}
if ($restartContainer) {
$this->tearDownContainer();
// Nemelo by byt třeba spouštět, všechny migrace proběhnou na začátku díky config.test.php
// $this->createSchema();
}
}
public function removeModule($module, $submodule = null)
{
$cfg = \KupShop\KupShopBundle\Config::get();
if ($submodule) {
$cfg['Modules'][$module][$submodule] = false;
} else {
$cfg['Modules'][$module] = false;
}
}
/**
* Returns the test database connection.
*
* @return \PHPUnit\DbUnit\Database\DefaultConnection
*/
public function getConnection()
{
return new \PHPUnit\DbUnit\Database\DefaultConnection(sqlGetConnection()->getWrappedConnection());
}
/**
* Returns the test dataset.
*
* @return \PHPUnit\DbUnit\DataSet\DefaultDataSet
*/
protected function getDataSet()
{
return new \PHPUnit\DbUnit\DataSet\DefaultDataSet();
}
/**
* Returns the database operation executed in test setup.
*
* @return \PHPUnit\DbUnit\Operation\Composite
*/
protected function getSetUpOperation()
{
return new \PHPUnit\DbUnit\Operation\Composite([
new \PHPUnit\DbUnit\Operation\DeleteAll(),
new \PHPUnit\DbUnit\Operation\Insert(),
]);
}
public function skipIfNoModule($moduleName)
{
if (!findModule($moduleName)) {
$this->markTestSkipped("Module '{$moduleName}' is disabled");
}
}
protected function suspendLogging($suspend)
{
static $logger = null;
if ($suspend) {
$this->assertNull($logger);
// Suspend SQL logging
$logger = sqlGetConnection()->getConfiguration()->getSQLLogger();
sqlGetConnection()->getConfiguration()->setSQLLogger(null);
} else {
// Resume SQL logging
sqlGetConnection()->getConfiguration()->setSQLLogger($logger);
$logger = null;
}
}
private function restoreDefaultLanguage()
{
global $txt_str;
if (is_null(self::$txt_str)) {
self::$txt_str = $txt_str;
}
$txt_str = self::$txt_str;
}
private function restoreDefaultConfig()
{
global $cfg;
if (is_null(self::$cfg)) {
self::$cfg = Config::get()->getContainer();
}
$cfg = self::$cfg;
}
protected function restoreDefaultCtrl()
{
global $ctrl;
$defaults = [
'id' => 0,
'admin' => 0,
'logged' => false,
'user_key' => '123456test123456',
'currency' => 'CZK',
'currUrl' => [
'Abs' => '',
'Rel' => '',
],
];
$ctrl = ServiceContainer::getService(\KupShop\KupShopBundle\Util\Compat\CtrlLoader::class);
$ctrl->setContainer($defaults);
return $ctrl;
}
private function restoreDefaultSettings()
{
global $dbcfg;
if (is_null(self::$dbcfg)) {
self::$dbcfg = Settings::getDefault();
}
$dbcfg = clone self::$dbcfg;
Settings::setDefault(['cs' => $dbcfg]);
}
protected function getContextManager()
{
if (!isset($this->contextManager)) {
$this->contextManager = ServiceContainer::getService(ContextManager::class);
}
return $this->contextManager;
}
private function setTestDefaults()
{
Cart::setCartID('123456');
$this->getContextManager()->forceEmptyContexts();
}
private function assertSameTransactionLevel()
{
$transactionLevel = sqlGetConnection()->getTransactionNestingLevel();
if ($this->transactionActivated && 1 !== $transactionLevel) {
$this->getTestResultObject()->stop();
$this->getTestResultObject()->addError(
$this,
new Exception($this->getTestMethodName().": The tested code ended up in a different transaction level ({$transactionLevel}) than it started in (1). Maybe missing parent::setUp() ?"),
0
);
}
}
private function assertNoChangesLeftInDatabase()
{
global $db;
if (!$db->checkDatabaseNotChanged()) {
$this->getTestResultObject()->stop();
$this->getTestResultObject()->addError(
$this,
new Exception($this->getTestMethodName().': Test left behind changes in the database.'),
0
);
}
}
/**
* Returns the dataset from JSON-encoded string.
*
* @param $string string JSON-encoded dataset
*
* @return \PHPUnit\DbUnit\DataSet\ArrayDataSet
*/
protected function getJsonDataSet($string)
{
return new \PHPUnit\DbUnit\DataSet\ArrayDataSet(json_decode_strict($string, true));
}
/**
* Returns the dataset from JSON file.
*
* @param $file string|null file name to load data from. Can be absolute, relative to test or null to use <testFileName>.json
*
* @return \PHPUnit\DbUnit\DataSet\ArrayDataSet
*/
protected function getJsonDataSetFromFile($file = null)
{
if ($file === null || !file_exists($file)) {
$classFile = (new ReflectionClass($this))->getFileName();
if ($file) {
$file = dirname($classFile).'/'.$file;
} else {
$file = str_replace('.php', '.json', $classFile);
}
}
return $this->getJsonDataSet(file_get_contents($file));
}
public function getTestMethodName()
{
return get_class($this).'::'.$this->getName();
}
protected function clearCaches()
{
Delivery::clearCache();
$this->get(\KupShop\CatalogBundle\Section\SectionTree::class)->clearCache();
Contexts::clear();
getLocalCache()->clear();
}
protected function updateModules()
{
}
public function initializeRequestStack(): void
{
ServiceContainer::getService('request_stack')->push(Request::createFromGlobals());
}
protected function switchLanguage($language = 'sk')
{
/** @var \KupShop\KupShopBundle\Context\LanguageContext $languageContext */
$languageContext = Contexts::get(\KupShop\KupShopBundle\Context\LanguageContext::class);
$languageContext->activate($language);
global $txt_str;
$translator = $this->get(\KupShop\KupShopBundle\Util\Locale\PHPArrayTranslator::class);
$txt_str = $translator->loadShopMainTranslations();
}
}