test fixes and added more tests

This commit is contained in:
Dennis Eichhorn 2021-10-02 20:49:17 +02:00
parent 2cf30d1073
commit 002112fca4
51 changed files with 763 additions and 430 deletions

View File

@ -205,7 +205,7 @@ final class BasicOcr
foreach ($candidateLabels as $i => $label) { foreach ($candidateLabels as $i => $label) {
$predictedLabels[] = [ $predictedLabels[] = [
'label' => $label, 'label' => $label,
'prob' => $countedCandidates[$candidateLabels[$i]] / $k, 'prob' => $countedCandidates[$label] / $k,
]; ];
} }
} }

View File

@ -97,7 +97,7 @@ class MazeGenerator
$pos = \array_pop($path); $pos = \array_pop($path);
if ($pos === null) { if ($pos === null) {
break; break; // @codeCoverageIgnore
} }
} }
} }

View File

@ -64,14 +64,16 @@ final class CycleSort implements SortInterface
++$pos; ++$pos;
} }
$old = $list[$pos]; if ($pos !== $start) {
$list[$pos] = $item; $old = $list[$pos];
$item = $old; $list[$pos] = $item;
$item = $old;
}
while ($pos !== $start) { while ($pos !== $start) {
$pos = $start; $pos = $start;
$length1 = \count($list);
for ($i = $start + 1; $i < $length1; ++$i) { for ($i = $start + 1; $i < $n; ++$i) {
if (!$list[$i]->compare($item, $order)) { if (!$list[$i]->compare($item, $order)) {
++$pos; ++$pos;
} }
@ -81,9 +83,11 @@ final class CycleSort implements SortInterface
++$pos; ++$pos;
} }
$old = $list[$pos]; if (!$item->equals($list[$pos])) {
$list[$pos] = $item; $old = $list[$pos];
$item = $old; $list[$pos] = $item;
$item = $old;
}
} }
} }

View File

@ -67,7 +67,7 @@ final class QuickSort implements SortInterface
{ {
if ($lo < $hi) { if ($lo < $hi) {
$i = self::partition($list, $lo, $hi, $order); $i = self::partition($list, $lo, $hi, $order);
self::qsort($list, $lo, $i, $order); self::qsort($list, $lo, $i - 1, $order);
self::qsort($list, $i + 1, $hi, $order); self::qsort($list, $i + 1, $hi, $order);
} }
} }
@ -86,26 +86,22 @@ final class QuickSort implements SortInterface
*/ */
private static function partition(array &$list, int $lo, int $hi, int $order) : int private static function partition(array &$list, int $lo, int $hi, int $order) : int
{ {
$pivot = $list[$lo + ((int) (($hi - $lo) / 2))]; $pivot = $list[$hi];
while (true) { $i = $lo - 1;
while (!$list[$lo]->compare($pivot, $order)) {
++$lo; for ($j = $lo; $j <= $hi - 1; ++$j) {
if (!$list[$j]->compare($pivot, $order)) {
++$i;
$old = $list[$i];
$list[$i] = $list[$j];
$list[$j] = $old;
} }
while ($list[$hi]->compare($pivot, $order)) {
--$hi;
}
if ($lo >= $hi) {
return $hi;
}
$old = $list[$lo];
$list[$lo] = $list[$hi];
$list[$hi] = $old;
++$lo;
--$hi;
} }
$old = $list[$i + 1];
$list[$i + 1] = $list[$hi];
$list[$hi] = $old;
return $i + 1;
} }
} }

View File

@ -98,11 +98,7 @@ final class ApplicationManager
$destination = \rtrim($destination, '\\/'); $destination = \rtrim($destination, '\\/');
$source = \rtrim($source, '/\\'); $source = \rtrim($source, '/\\');
if (!\is_dir($source) || \is_dir($destination)) { if (!\is_dir($source) || \is_dir($destination) || !\is_file($source . '/Admin/Installer.php')) {
return false;
}
if (!\is_file($source . '/Admin/Installer.php')) {
return false; return false;
} }
@ -124,6 +120,73 @@ final class ApplicationManager
} }
} }
/**
* Uninstall the application
*
* @param string $source Source of the application
*
* @return bool
*
* @since 1.0.0
*/
public function uninstall(string $source) : bool
{
$source = \rtrim($source, '/\\');
if (!\is_dir($source) || !\is_file($source . '/Admin/Uninstaller.php')) {
return false;
}
try {
$info = $this->loadInfo($source . '/info.json');
$this->installed[$info->getInternalName()] = $info;
$classPath = \substr(\realpath($source) . '/Admin/Uninstaller', $t = \strlen(\realpath(__DIR__ . '/../../')));
$class = \str_replace('/', '\\', $classPath);
$class::uninstall($this->app->dbPool, $info, $this->app->appSettings);
$this->uninstallFiles($source);
return true;
} catch (\Throwable $t) {
return false; // @codeCoverageIgnore
}
}
/**
* Re-init application.
*
* @param string $appPath App path
*
* @return void
*
* @throws InvalidModuleException Throws this exception in case the installer doesn't exist
*
* @since 1.0.0
*/
public function reInit(string $appPath) : void
{
$info = $this->loadInfo($appPath . '/info.json');
if ($info === null) {
return;
}
$classPath = \substr(\realpath($appPath) . '/Admin/Installer', \strlen(\realpath(__DIR__ . '/../../')));
$class = \str_replace('/', '\\', $classPath);
/** @var $class InstallerAbstract */
$class::reInit($info);
}
/**
* Get all applications who are providing for a specific module.
*
* @param string $module Module to check providings for
*
* @return array<string, string[]>
*
* @since 1.0.0
*/
public function getProvidingForModule(string $module) : array public function getProvidingForModule(string $module) : array
{ {
$providing = []; $providing = [];
@ -189,6 +252,20 @@ final class ApplicationManager
Directory::copy($source, $destination); Directory::copy($source, $destination);
} }
/**
* Uninstall files
*
* @param string $source Source path
*
* @return void
*
* @since 1.0.0
*/
private function uninstallFiles(string $source) : void
{
Directory::delete($source);
}
/** /**
* Replace placeholder string (application placeholder name) * Replace placeholder string (application placeholder name)
* *

View File

@ -143,6 +143,10 @@ abstract class InstallerAbstract
$classPath = \substr(\realpath(static::PATH) . '/Status', \strlen(\realpath(__DIR__ . '/../../'))); $classPath = \substr(\realpath(static::PATH) . '/Status', \strlen(\realpath(__DIR__ . '/../../')));
$class = \str_replace('/', '\\', $classPath); $class = \str_replace('/', '\\', $classPath);
$class::clearRoutes();
$class::clearHooks();
$class::activateRoutes($info); $class::activateRoutes($info);
$class::activateHooks($info); $class::activateHooks($info);
} }

View File

@ -63,7 +63,7 @@ abstract class StatusAbstract
*/ */
public static function activateRoutes(ApplicationInfo $appInfo = null) : void public static function activateRoutes(ApplicationInfo $appInfo = null) : void
{ {
self::installRoutes(static::PATH . '/../Routes.php', static::PATH . '/../Admin/Install/Application/Routes.php'); self::installRoutesHooks(static::PATH . '/../Routes.php', static::PATH . '/../Admin/Install/Application/Routes.php');
} }
/** /**
@ -79,7 +79,7 @@ abstract class StatusAbstract
*/ */
public static function activateHooks(ApplicationInfo $appInfo = null) : void public static function activateHooks(ApplicationInfo $appInfo = null) : void
{ {
self::installRoutes(static::PATH . '/../Hooks.php', static::PATH . '/../Admin/Install/Application/Hooks.php'); self::installRoutesHooks(static::PATH . '/../Hooks.php', static::PATH . '/../Admin/Install/Application/Hooks.php');
} }
/** /**
@ -94,7 +94,7 @@ abstract class StatusAbstract
* *
* @since 1.0.0 * @since 1.0.0
*/ */
protected static function installRoutes(string $destRoutePath, string $srcRoutePath) : void protected static function installRoutesHooks(string $destRoutePath, string $srcRoutePath) : void
{ {
if (!\is_file($destRoutePath)) { if (!\is_file($destRoutePath)) {
\file_put_contents($destRoutePath, '<?php return [];'); \file_put_contents($destRoutePath, '<?php return [];');
@ -115,175 +115,40 @@ abstract class StatusAbstract
/** @noinspection PhpIncludeInspection */ /** @noinspection PhpIncludeInspection */
$appRoutes = include $destRoutePath; $appRoutes = include $destRoutePath;
/** @noinspection PhpIncludeInspection */ /** @noinspection PhpIncludeInspection */
$moduleRoutes = include $srcRoutePath; $srcRoutes = include $srcRoutePath;
$appRoutes = \array_merge_recursive($appRoutes, $moduleRoutes); $appRoutes = \array_merge_recursive($appRoutes, $srcRoutes);
\file_put_contents($destRoutePath, '<?php return ' . ArrayParser::serializeArray($appRoutes) . ';', \LOCK_EX); \file_put_contents($destRoutePath, '<?php return ' . ArrayParser::serializeArray($appRoutes) . ';', \LOCK_EX);
} }
/** /**
* Install hooks. * Clear all routes.
*
* @param string $destHookPath Destination hook path
* @param string $srcHookPath Source hook path
*
* @return void
*
* @throws PathException This exception is thrown if the hook file doesn't exist
* @throws PermissionException This exception is thrown if the hook file couldn't be updated (no write permission)
*
* @since 1.0.0
*/
protected static function installHooks(string $destHookPath, string $srcHookPath) : void
{
if (!\is_file($destHookPath)) {
\file_put_contents($destHookPath, '<?php return [];');
}
if (!\is_file($srcHookPath)) {
return;
}
if (!\is_file($destHookPath)) {
throw new PathException($destHookPath);
}
if (!\is_writable($destHookPath)) {
throw new PermissionException($destHookPath);
}
/** @noinspection PhpIncludeInspection */
$appHooks = include $destHookPath;
/** @noinspection PhpIncludeInspection */
$moduleHooks = include $srcHookPath;
$appHooks = \array_merge_recursive($appHooks, $moduleHooks);
\file_put_contents($destHookPath, '<?php return ' . ArrayParser::serializeArray($appHooks) . ';', \LOCK_EX);
}
/**
* Deactivate routes.
*
* @param ApplicationInfo $appInfo Application info
* *
* @return void * @return void
* *
* @throws PathException
* @throws PermissionException * @throws PermissionException
* *
* @since 1.0.0 * @since 1.0.0
*/ */
public static function deactivateRoutes(ApplicationInfo $appInfo) : void public static function clearRoutes() : void
{ {
self::installRoutes(static::PATH . '/../Routes.php', static::PATH . '/../Admin/Install/Application/Routes.php'); \file_put_contents(static::PATH . '/../Routes.php', '<?php return [];', \LOCK_EX);
} }
/** /**
* Deactivate hooks. * Clear all hooks.
*
* @param ApplicationInfo $appInfo Application info
* *
* @return void * @return void
* *
* @throws PathException
* @throws PermissionException * @throws PermissionException
* *
* @since 1.0.0 * @since 1.0.0
*/ */
public static function deactivateHooks(ApplicationInfo $appInfo) : void public static function clearHooks() : void
{ {
self::installRoutes(static::PATH . '/../Hooks.php', static::PATH . '/../Admin/Install/Application/Hooks.php'); \file_put_contents(static::PATH . '/../Hooks.php', '<?php return [];', \LOCK_EX);
}
/**
* Uninstall routes.
*
* @param string $destRoutePath Destination route path
* @param string $srcRoutePath Source route path
*
* @return void
*
* @throws PermissionException
*
* @since 1.0.0
*/
public static function uninstallRoutes(string $destRoutePath, string $srcRoutePath) : void
{
if (!\is_file($destRoutePath)
|| !\is_file($srcRoutePath)
) {
return;
}
if (!\is_file($destRoutePath)) {
throw new PathException($destRoutePath);
}
if (!\is_writable($destRoutePath)) {
throw new PermissionException($destRoutePath);
}
/** @noinspection PhpIncludeInspection */
$appRoutes = include $destRoutePath;
/** @noinspection PhpIncludeInspection */
$moduleRoutes = include $srcRoutePath;
$appRoutes = ArrayUtils::array_diff_assoc_recursive($appRoutes, $moduleRoutes);
\file_put_contents($destRoutePath, '<?php return ' . ArrayParser::serializeArray($appRoutes) . ';', \LOCK_EX);
}
/**
* Uninstall hooks.
*
* @param string $destHookPath Destination hook path
* @param string $srcHookPath Source hook path
*
* @return void
*
* @throws PermissionException
*
* @since 1.0.0
*/
protected static function uninstallHooks(string $destHookPath, string $srcHookPath) : void
{
if (!\is_file($destHookPath)
|| !\is_file($srcHookPath)
) {
return;
}
if (!\is_file($destHookPath)) {
throw new PathException($destHookPath);
}
if (!\is_writable($destHookPath)) {
throw new PermissionException($destHookPath);
}
/** @noinspection PhpIncludeInspection */
$appHooks = include $destHookPath;
/** @noinspection PhpIncludeInspection */
$moduleHooks = include $srcHookPath;
$appHooks = ArrayUtils::array_diff_assoc_recursive($appHooks, $moduleHooks);
\file_put_contents($destHookPath, '<?php return ' . ArrayParser::serializeArray($appHooks) . ';', \LOCK_EX);
}
/**
* Deactivate app.
*
* @param DatabasePool $dbPool Database instance
* @param ApplicationInfo $info Module info
*
* @return void
*
* @since 1.0.0
*/
public static function deactivate(DatabasePool $dbPool, ApplicationInfo $info) : void
{
self::deactivateRoutes($info);
self::deactivateHooks($info);
} }
} }

View File

@ -40,7 +40,7 @@ abstract class UninstallerAbstract
*/ */
public static function uninstall(DatabasePool $dbPool, ApplicationInfo $info) : void public static function uninstall(DatabasePool $dbPool, ApplicationInfo $info) : void
{ {
self::deactivate($dbPool, $info); //self::deactivate($dbPool, $info);
self::dropTables($dbPool, $info); self::dropTables($dbPool, $info);
self::unregisterFromDatabase($dbPool, $info); self::unregisterFromDatabase($dbPool, $info);
} }
@ -55,12 +55,14 @@ abstract class UninstallerAbstract
* *
* @since 1.0.0 * @since 1.0.0
*/ */
/*
protected static function deactivate(DatabasePool $dbPool, ApplicationInfo $info) : void protected static function deactivate(DatabasePool $dbPool, ApplicationInfo $info) : void
{ {
/** @var StatusAbstract $class */ $classPath = \substr(\realpath(static::PATH) . '/Status', \strlen(\realpath(__DIR__ . '/../../')));
$class = '\Web\\' . $info->getInternalName() . '\Admin\Status';
$class = \str_replace('/', '\\', $classPath);
$class::deactivate($dbPool, $info); $class::deactivate($dbPool, $info);
} }*/
/** /**
* Drop tables of app. * Drop tables of app.
@ -74,8 +76,7 @@ abstract class UninstallerAbstract
*/ */
public static function dropTables(DatabasePool $dbPool, ApplicationInfo $info) : void public static function dropTables(DatabasePool $dbPool, ApplicationInfo $info) : void
{ {
$path = __DIR__ . '/../../Web/' . $info->getInternalName() . '/Admin/Install/db.json'; $path = static::PATH . '/Install/db.json';
if (!\is_file($path)) { if (!\is_file($path)) {
return; return;
} }
@ -88,8 +89,8 @@ abstract class UninstallerAbstract
$definitions = \json_decode($content, true); $definitions = \json_decode($content, true);
$builder = new SchemaBuilder($dbPool->get('schema')); $builder = new SchemaBuilder($dbPool->get('schema'));
foreach ($definitions as $definition) { foreach ($definitions as $name => $definition) {
$builder->dropTable($definition['table'] ?? ''); $builder->dropTable($name ?? '');
} }
$builder->execute(); $builder->execute();

View File

@ -27,7 +27,7 @@ final class CustomerValue
/** /**
* Simple customer lifetime value * Simple customer lifetime value
* *
* Hazard Model, same as $margin * (1 + $discountRate) / (1 + $discountRate - $retentionRate) * Hazard Model
* *
* @param float $margin Margin per period (or revenue/sales) * @param float $margin Margin per period (or revenue/sales)
* @param float $retentionRate Rate of remaining customers per period (= average lifetime / (1 + average lifetime)) * @param float $retentionRate Rate of remaining customers per period (= average lifetime / (1 + average lifetime))
@ -42,32 +42,6 @@ final class CustomerValue
return $margin * $retentionRate / (1 + $discountRate - $retentionRate); return $margin * $retentionRate / (1 + $discountRate - $retentionRate);
} }
/**
* Basic customer lifetime value
*
* Hazard Model, same as $margin * (1 + $discountRate) / (1 + $discountRate - $retentionRate)
*
* @param array $margins Margin per period (or revenue/sales)
* @param float $retentionRate Rate of remaining customers per period (= average lifetime / (1 + average lifetime))
* @param float $discountRate Cost of capital to discount future revenue
*
* @return float
*
* @since 1.0.0
*/
public static function getBasicCLV(array $margins, float $retentionRate, float $discountRate) : float
{
$clv = 0.0;
$c = 1;
foreach ($margins as $margin) {
$clv += ($retentionRate ** $c) * $margin * \pow(1 / (1 + $discountRate), $c);
++$c;
}
return $clv;
}
/** /**
* Normalized measure of recurring revenue * Normalized measure of recurring revenue
* *

View File

@ -90,26 +90,12 @@ final class Metrics
return $rc * (1 - \exp(-$r * $t)); return $rc * (1 - \exp(-$r * $t));
} }
/**
* Calculate the average lifetime duration
*
* @param array $retainedCustomers Retained customers per period
*
* @return float
*
* @since 1.0.0
*/
public static function averageLifetimeDuration(array $retainedCustomers) : float
{
return \array_sum($retainedCustomers) / \count($retainedCustomers);
}
/** /**
* Calculate the probability of a customer being active * Calculate the probability of a customer being active
* *
* @param int $purchases Number of purchases during the periods * @param int $purchases Number of purchases during the periods
* @param int $periods Number of periods (e.g. number of months) * @param int $periods Number of periods (e.g. number of months)
* @param int $lastPurchase In which period was the last purchase * @param int $lastPurchase In which period was the last purchase (lastPurchase = periods: means customer purchased in this period)
* *
* @return float * @return float
* *

View File

@ -45,11 +45,11 @@ interface ConnectionInterface extends DataStorageConnectionInterface
* @param int|string $key Unique cache key * @param int|string $key Unique cache key
* @param int $value By value * @param int $value By value
* *
* @return void * @return bool
* *
* @since 1.0.0 * @since 1.0.0
*/ */
public function increment(int | string $key, int $value = 1) : void; public function increment(int | string $key, int $value = 1) : bool;
/** /**
* Decrement value. * Decrement value.
@ -57,11 +57,11 @@ interface ConnectionInterface extends DataStorageConnectionInterface
* @param int|string $key Unique cache key * @param int|string $key Unique cache key
* @param int $value By value * @param int $value By value
* *
* @return void * @return bool
* *
* @since 1.0.0 * @since 1.0.0
*/ */
public function decrement(int | string $key, int $value = 1) : void; public function decrement(int | string $key, int $value = 1) : bool;
/** /**
* Rename cache key. * Rename cache key.

View File

@ -238,7 +238,7 @@ final class FileCache extends ConnectionAbstract
return ''; return '';
} }
throw new InvalidEnumValue($type); throw new InvalidEnumValue($type); // @codeCoverageIgnore
} }
/** /**
@ -281,7 +281,7 @@ final class FileCache extends ConnectionAbstract
$raw = \file_get_contents($path); $raw = \file_get_contents($path);
if ($raw === false) { if ($raw === false) {
return null; return null; // @codeCoverageIgnore
} }
$type = (int) $raw[0]; $type = (int) $raw[0];
@ -289,7 +289,7 @@ final class FileCache extends ConnectionAbstract
$expireEnd = (int) \strpos($raw, self::DELIM, $expireStart + 1); $expireEnd = (int) \strpos($raw, self::DELIM, $expireStart + 1);
if ($expireStart < 0 || $expireEnd < 0) { if ($expireStart < 0 || $expireEnd < 0) {
return null; return null; // @codeCoverageIgnore
} }
$cacheExpire = \substr($raw, $expireStart + 1, $expireEnd - ($expireStart + 1)); $cacheExpire = \substr($raw, $expireStart + 1, $expireEnd - ($expireStart + 1));
@ -337,7 +337,7 @@ final class FileCache extends ConnectionAbstract
$namespace = \substr($raw, $namespaceStart + 1, $namespaceEnd - $namespaceStart - 1); $namespace = \substr($raw, $namespaceStart + 1, $namespaceEnd - $namespaceStart - 1);
if ($namespace === false) { if ($namespace === false) {
return null; return null; // @codeCoverageIgnore
} }
return new $namespace(); return new $namespace();
@ -347,7 +347,7 @@ final class FileCache extends ConnectionAbstract
$namespace = \substr($raw, $namespaceStart + 1, $namespaceEnd - $namespaceStart - 1); $namespace = \substr($raw, $namespaceStart + 1, $namespaceEnd - $namespaceStart - 1);
if ($namespace === false) { if ($namespace === false) {
return null; return null; // @codeCoverageIgnore
} }
$obj = new $namespace(); $obj = new $namespace();
@ -385,7 +385,7 @@ final class FileCache extends ConnectionAbstract
$raw = \file_get_contents($path); $raw = \file_get_contents($path);
if ($raw === false) { if ($raw === false) {
return false; return false; // @codeCoverageIgnore
} }
$cacheExpire = $this->getExpire($raw); $cacheExpire = $this->getExpire($raw);
@ -426,7 +426,7 @@ final class FileCache extends ConnectionAbstract
$raw = \file_get_contents($path); $raw = \file_get_contents($path);
if ($raw === false) { if ($raw === false) {
return false; return false; // @codeCoverageIgnore
} }
$type = (int) $raw[0]; $type = (int) $raw[0];
@ -434,7 +434,7 @@ final class FileCache extends ConnectionAbstract
$expireEnd = (int) \strpos($raw, self::DELIM, $expireStart + 1); $expireEnd = (int) \strpos($raw, self::DELIM, $expireStart + 1);
if ($expireStart < 0 || $expireEnd < 0) { if ($expireStart < 0 || $expireEnd < 0) {
return false; return false; // @codeCoverageIgnore
} }
$cacheExpire = \substr($raw, $expireStart + 1, $expireEnd - ($expireStart + 1)); $cacheExpire = \substr($raw, $expireStart + 1, $expireEnd - ($expireStart + 1));
@ -452,11 +452,11 @@ final class FileCache extends ConnectionAbstract
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function increment(int | string $key, int $value = 1) : void public function increment(int | string $key, int $value = 1) : bool
{ {
$path = $this->getPath($key); $path = $this->getPath($key);
if (!File::exists($path)) { if (!File::exists($path)) {
return; return false;
} }
$created = File::created($path)->getTimestamp(); $created = File::created($path)->getTimestamp();
@ -464,7 +464,7 @@ final class FileCache extends ConnectionAbstract
$raw = \file_get_contents($path); $raw = \file_get_contents($path);
if ($raw === false) { if ($raw === false) {
return; return false; // @codeCoverageIgnore
} }
$type = (int) $raw[0]; $type = (int) $raw[0];
@ -472,7 +472,7 @@ final class FileCache extends ConnectionAbstract
$expireEnd = (int) \strpos($raw, self::DELIM, $expireStart + 1); $expireEnd = (int) \strpos($raw, self::DELIM, $expireStart + 1);
if ($expireStart < 0 || $expireEnd < 0) { if ($expireStart < 0 || $expireEnd < 0) {
return; return false; // @codeCoverageIgnore
} }
$cacheExpire = \substr($raw, $expireStart + 1, $expireEnd - ($expireStart + 1)); $cacheExpire = \substr($raw, $expireStart + 1, $expireEnd - ($expireStart + 1));
@ -480,16 +480,18 @@ final class FileCache extends ConnectionAbstract
$val = $this->reverseValue($type, $raw, $expireEnd); $val = $this->reverseValue($type, $raw, $expireEnd);
$this->set($key, $val + $value, $cacheExpire); $this->set($key, $val + $value, $cacheExpire);
return true;
} }
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function decrement(int | string $key, int $value = 1) : void public function decrement(int | string $key, int $value = 1) : bool
{ {
$path = $this->getPath($key); $path = $this->getPath($key);
if (!File::exists($path)) { if (!File::exists($path)) {
return; return false;
} }
$created = File::created($path)->getTimestamp(); $created = File::created($path)->getTimestamp();
@ -497,7 +499,7 @@ final class FileCache extends ConnectionAbstract
$raw = \file_get_contents($path); $raw = \file_get_contents($path);
if ($raw === false) { if ($raw === false) {
return; return false; // @codeCoverageIgnore
} }
$type = (int) $raw[0]; $type = (int) $raw[0];
@ -505,7 +507,7 @@ final class FileCache extends ConnectionAbstract
$expireEnd = (int) \strpos($raw, self::DELIM, $expireStart + 1); $expireEnd = (int) \strpos($raw, self::DELIM, $expireStart + 1);
if ($expireStart < 0 || $expireEnd < 0) { if ($expireStart < 0 || $expireEnd < 0) {
return; return false; // @codeCoverageIgnore
} }
$cacheExpire = \substr($raw, $expireStart + 1, $expireEnd - ($expireStart + 1)); $cacheExpire = \substr($raw, $expireStart + 1, $expireEnd - ($expireStart + 1));
@ -513,6 +515,8 @@ final class FileCache extends ConnectionAbstract
$val = $this->reverseValue($type, $raw, $expireEnd); $val = $this->reverseValue($type, $raw, $expireEnd);
$this->set($key, $val - $value, $cacheExpire); $this->set($key, $val - $value, $cacheExpire);
return true;
} }
/** /**
@ -548,7 +552,7 @@ final class FileCache extends ConnectionAbstract
$raw = \file_get_contents($path); $raw = \file_get_contents($path);
if ($raw === false) { if ($raw === false) {
continue; continue; // @codeCoverageIgnore
} }
$type = (int) $raw[0]; $type = (int) $raw[0];
@ -556,7 +560,7 @@ final class FileCache extends ConnectionAbstract
$expireEnd = (int) \strpos($raw, self::DELIM, $expireStart + 1); $expireEnd = (int) \strpos($raw, self::DELIM, $expireStart + 1);
if ($expireStart < 0 || $expireEnd < 0) { if ($expireStart < 0 || $expireEnd < 0) {
continue; continue; // @codeCoverageIgnore
} }
$cacheExpire = \substr($raw, $expireStart + 1, $expireEnd - ($expireStart + 1)); $cacheExpire = \substr($raw, $expireStart + 1, $expireEnd - ($expireStart + 1));
@ -600,7 +604,7 @@ final class FileCache extends ConnectionAbstract
$raw = \file_get_contents($path); $raw = \file_get_contents($path);
if ($raw === false) { if ($raw === false) {
continue; continue; // @codeCoverageIgnore
} }
$cacheExpire = $this->getExpire($raw); $cacheExpire = $this->getExpire($raw);

View File

@ -154,17 +154,21 @@ final class MemCached extends ConnectionAbstract
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function increment(int | string $key, int $value = 1) : void public function increment(int | string $key, int $value = 1) : bool
{ {
$this->con->increment($key, $value); $this->con->increment($key, $value);
return true;
} }
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function decrement(int | string $key, int $value = 1) : void public function decrement(int | string $key, int $value = 1) : bool
{ {
$this->con->decrement($key, $value); $this->con->decrement($key, $value);
return true;
} }
/** /**

View File

@ -41,15 +41,17 @@ final class NullCache extends ConnectionAbstract
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function increment(int | string $key, int $value = 1) : void public function increment(int | string $key, int $value = 1) : bool
{ {
return true;
} }
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function decrement(int | string $key, int $value = 1) : void public function decrement(int | string $key, int $value = 1) : bool
{ {
return true;
} }
/** /**

View File

@ -182,17 +182,21 @@ final class RedisCache extends ConnectionAbstract
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function increment(int | string $key, int $value = 1) : void public function increment(int | string $key, int $value = 1) : bool
{ {
$this->con->incrBy($key, $value); $this->con->incrBy($key, $value);
return true;
} }
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function decrement(int | string $key, int $value = 1) : void public function decrement(int | string $key, int $value = 1) : bool
{ {
$this->con->decrBy($key, $value); $this->con->decrBy($key, $value);
return true;
} }
/** /**

View File

@ -54,10 +54,10 @@ class Builder extends QueryBuilder
/** /**
* Table to drop. * Table to drop.
* *
* @var string * @var array
* @since 1.0.0 * @since 1.0.0
*/ */
public string $dropTable = ''; public array $dropTable = [];
/** /**
* Tables. * Tables.
@ -192,8 +192,8 @@ class Builder extends QueryBuilder
*/ */
public function dropTable(string $table) : self public function dropTable(string $table) : self
{ {
$this->type = QueryType::DROP_TABLE; $this->type = QueryType::DROP_TABLE;
$this->dropTable = $table; $this->dropTable[] = $table;
return $this; return $this;
} }

View File

@ -232,16 +232,16 @@ class Grammar extends QueryGrammar
/** /**
* Compile drop query. * Compile drop query.
* *
* @param BuilderAbstract $query Query * @param BuilderAbstract $query Query
* @param string $table Tables to drop * @param string $database Tables to drop
* *
* @return string * @return string
* *
* @since 1.0.0 * @since 1.0.0
*/ */
protected function compileDropDatabase(BuilderAbstract $query, string $table) : string protected function compileDropDatabase(BuilderAbstract $query, string $database) : string
{ {
$expression = $this->expressionizeTableColumn([$table]); $expression = $this->expressionizeTableColumn([$database]);
if ($expression === '') { if ($expression === '') {
$expression = '*'; $expression = '*';
@ -253,16 +253,16 @@ class Grammar extends QueryGrammar
/** /**
* Compile drop query. * Compile drop query.
* *
* @param BuilderAbstract $query Query * @param BuilderAbstract $query Query
* @param string $table Tables to drop * @param array $tables Tables to drop
* *
* @return string * @return string
* *
* @since 1.0.0 * @since 1.0.0
*/ */
protected function compileDropTable(BuilderAbstract $query, string $table) : string protected function compileDropTable(BuilderAbstract $query, array $tables) : string
{ {
$expression = $this->expressionizeTableColumn([$table]); $expression = $this->expressionizeTableColumn($tables);
if ($expression === '') { if ($expression === '') {
$expression = '*'; $expression = '*';

View File

@ -142,7 +142,7 @@ final class Prime
$primes = \array_combine($range, $range); $primes = \array_combine($range, $range);
if ($primes === false) { if ($primes === false) {
return []; return []; // @codeCoverageIgnore
} }
while ($number * $number < $n) { while ($number * $number < $n) {

View File

@ -121,7 +121,7 @@ abstract class ModuleAbstract
public static function getLocalization(string $language, string $destination) : array public static function getLocalization(string $language, string $destination) : array
{ {
$lang = []; $lang = [];
if (\is_file($oldPath = static::PATH . static::NAME . '/Theme/' . $destination . '/Lang/' . $language . '.lang.php')) { if (\is_file($oldPath = static::PATH . '/Theme/' . $destination . '/Lang/' . $language . '.lang.php')) {
/** @noinspection PhpIncludeInspection */ /** @noinspection PhpIncludeInspection */
return include $oldPath; return include $oldPath;
} }

View File

@ -77,7 +77,7 @@ abstract class StatusAbstract
continue; continue;
} }
self::installRoutes(__DIR__ . '/../../' . $child->getName() . '/' . \basename($file->getName(), '.php') . '/Routes.php', $file->getPath()); self::installRoutesHooks(__DIR__ . '/../../' . $child->getName() . '/' . \basename($file->getName(), '.php') . '/Routes.php', $file->getPath());
} }
} elseif ($child instanceof File) { } elseif ($child instanceof File) {
if (!\is_dir(__DIR__ . '/../../' . $child->getName()) if (!\is_dir(__DIR__ . '/../../' . $child->getName())
@ -86,7 +86,7 @@ abstract class StatusAbstract
continue; continue;
} }
self::installRoutes(__DIR__ . '/../../' . $child->getName() . '/Routes.php', $child->getPath()); self::installRoutesHooks(__DIR__ . '/../../' . $child->getName() . '/Routes.php', $child->getPath());
} }
} }
} }
@ -103,7 +103,7 @@ abstract class StatusAbstract
* *
* @since 1.0.0 * @since 1.0.0
*/ */
protected static function installRoutes(string $destRoutePath, string $srcRoutePath) : void protected static function installRoutesHooks(string $destRoutePath, string $srcRoutePath) : void
{ {
if (!\is_file($destRoutePath)) { if (!\is_file($destRoutePath)) {
\file_put_contents($destRoutePath, '<?php return [];'); \file_put_contents($destRoutePath, '<?php return [];');
@ -157,7 +157,7 @@ abstract class StatusAbstract
continue; continue;
} }
self::installHooks(__DIR__ . '/../../' . $child->getName() . '/' . \basename($file->getName(), '.php') . '/Hooks.php', $file->getPath()); self::installRoutesHooks(__DIR__ . '/../../' . $child->getName() . '/' . \basename($file->getName(), '.php') . '/Hooks.php', $file->getPath());
} }
} elseif ($child instanceof File) { } elseif ($child instanceof File) {
if (!\is_dir(__DIR__ . '/../../' . $child->getName()) if (!\is_dir(__DIR__ . '/../../' . $child->getName())
@ -166,52 +166,11 @@ abstract class StatusAbstract
continue; continue;
} }
self::installHooks(__DIR__ . '/../../' . $child->getName() . '/Hooks.php', $child->getPath()); self::installRoutesHooks(__DIR__ . '/../../' . $child->getName() . '/Hooks.php', $child->getPath());
} }
} }
} }
/**
* Install hooks.
*
* @param string $destHookPath Destination hook path
* @param string $srcHookPath Source hook path
*
* @return void
*
* @throws PathException This exception is thrown if the hook file doesn't exist
* @throws PermissionException This exception is thrown if the hook file couldn't be updated (no write permission)
*
* @since 1.0.0
*/
protected static function installHooks(string $destHookPath, string $srcHookPath) : void
{
if (!\is_file($destHookPath)) {
\file_put_contents($destHookPath, '<?php return [];');
}
if (!\is_file($srcHookPath)) {
return;
}
if (!\is_file($destHookPath)) {
throw new PathException($destHookPath);
}
if (!\is_writable($destHookPath)) {
throw new PermissionException($destHookPath);
}
/** @noinspection PhpIncludeInspection */
$appHooks = include $destHookPath;
/** @noinspection PhpIncludeInspection */
$moduleHooks = include $srcHookPath;
$appHooks = \array_merge_recursive($appHooks, $moduleHooks);
\file_put_contents($destHookPath, '<?php return ' . ArrayParser::serializeArray($appHooks) . ';', \LOCK_EX);
}
/** /**
* Deactivate module. * Deactivate module.
* *
@ -252,7 +211,7 @@ abstract class StatusAbstract
continue; continue;
} }
self::uninstallRoutes(__DIR__ . '/../../' . $child->getName() . '/' . \basename($file->getName(), '.php') . '/Routes.php', $file->getPath()); self::uninstallRoutesHooks(__DIR__ . '/../../' . $child->getName() . '/' . \basename($file->getName(), '.php') . '/Routes.php', $file->getPath());
} }
} elseif ($child instanceof File) { } elseif ($child instanceof File) {
if (!\is_dir(__DIR__ . '/../../' . $child->getName()) if (!\is_dir(__DIR__ . '/../../' . $child->getName())
@ -261,7 +220,7 @@ abstract class StatusAbstract
continue; continue;
} }
self::uninstallRoutes(__DIR__ . '/../../' . $child->getName() . '/Routes.php', $child->getPath()); self::uninstallRoutesHooks(__DIR__ . '/../../' . $child->getName() . '/Routes.php', $child->getPath());
} }
} }
} }
@ -278,7 +237,7 @@ abstract class StatusAbstract
* *
* @since 1.0.0 * @since 1.0.0
*/ */
public static function uninstallRoutes(string $destRoutePath, string $srcRoutePath) : void public static function uninstallRoutesHooks(string $destRoutePath, string $srcRoutePath) : void
{ {
if (!\is_file($destRoutePath) if (!\is_file($destRoutePath)
|| !\is_file($srcRoutePath) || !\is_file($srcRoutePath)
@ -328,7 +287,7 @@ abstract class StatusAbstract
continue; continue;
} }
self::uninstallHooks(__DIR__ . '/../../' . $child->getName() . '/' . \basename($file->getName(), '.php') . '/Hooks.php', $file->getPath()); self::uninstallRoutesHooks(__DIR__ . '/../../' . $child->getName() . '/' . \basename($file->getName(), '.php') . '/Hooks.php', $file->getPath());
} }
} elseif ($child instanceof File) { } elseif ($child instanceof File) {
if (!\is_dir(__DIR__ . '/../../' . $child->getName()) if (!\is_dir(__DIR__ . '/../../' . $child->getName())
@ -337,46 +296,8 @@ abstract class StatusAbstract
continue; continue;
} }
self::uninstallHooks(__DIR__ . '/../../' . $child->getName() . '/Hooks.php', $child->getPath()); self::uninstallRoutesHooks(__DIR__ . '/../../' . $child->getName() . '/Hooks.php', $child->getPath());
} }
} }
} }
/**
* Uninstall hooks.
*
* @param string $destHookPath Destination hook path
* @param string $srcHookPath Source hook path
*
* @return void
*
* @throws PermissionException
*
* @since 1.0.0
*/
protected static function uninstallHooks(string $destHookPath, string $srcHookPath) : void
{
if (!\is_file($destHookPath)
|| !\is_file($srcHookPath)
) {
return;
}
if (!\is_file($destHookPath)) {
throw new PathException($destHookPath);
}
if (!\is_writable($destHookPath)) {
throw new PermissionException($destHookPath);
}
/** @noinspection PhpIncludeInspection */
$appHooks = include $destHookPath;
/** @noinspection PhpIncludeInspection */
$moduleHooks = include $srcHookPath;
$appHooks = ArrayUtils::array_diff_assoc_recursive($appHooks, $moduleHooks);
\file_put_contents($destHookPath, '<?php return ' . ArrayParser::serializeArray($appHooks) . ';', \LOCK_EX);
}
} }

View File

@ -88,8 +88,8 @@ abstract class UninstallerAbstract
$definitions = \json_decode($content, true); $definitions = \json_decode($content, true);
$builder = new SchemaBuilder($dbPool->get('schema')); $builder = new SchemaBuilder($dbPool->get('schema'));
foreach ($definitions as $definition) { foreach ($definitions as $name => $definition) {
$builder->dropTable($definition['table'] ?? ''); $builder->dropTable($name ?? '');
} }
$builder->execute(); $builder->execute();

View File

@ -18,6 +18,7 @@ use phpOMS\Account\Account;
use phpOMS\Account\AccountStatus; use phpOMS\Account\AccountStatus;
use phpOMS\Account\AccountType; use phpOMS\Account\AccountType;
use phpOMS\Account\Group; use phpOMS\Account\Group;
use phpOMS\Account\NullGroup;
use phpOMS\Account\PermissionAbstract; use phpOMS\Account\PermissionAbstract;
use phpOMS\Account\PermissionType; use phpOMS\Account\PermissionType;
use phpOMS\Localization\L11nManager; use phpOMS\Localization\L11nManager;
@ -107,6 +108,7 @@ class AccountTest extends \PHPUnit\Framework\TestCase
self::assertEquals(AccountType::USER, $account->getType()); self::assertEquals(AccountType::USER, $account->getType());
self::assertEquals([], $account->getPermissions()); self::assertEquals([], $account->getPermissions());
self::assertFalse($account->hasGroup(2));
self::assertInstanceOf('\DateTimeInterface', $account->getLastActive()); self::assertInstanceOf('\DateTimeInterface', $account->getLastActive());
self::assertInstanceOf('\DateTimeImmutable', $account->createdAt); self::assertInstanceOf('\DateTimeImmutable', $account->createdAt);
@ -151,8 +153,9 @@ class AccountTest extends \PHPUnit\Framework\TestCase
$account = new Account(); $account = new Account();
$account->generatePassword('abcd'); $account->generatePassword('abcd');
$account->addGroup(new Group()); $account->addGroup(new NullGroup(2));
self::assertCount(1, $account->getGroups()); self::assertCount(1, $account->getGroups());
self::assertTrue($account->hasGroup(2));
} }
/** /**

View File

@ -32,9 +32,9 @@ class WeightedTest extends \PHPUnit\Framework\TestCase
public function testNoOverlappingScheduling() : void public function testNoOverlappingScheduling() : void
{ {
$jobs = [ $jobs = [
new Job(10, new \DateTime('2000-01-01'), null, '0'),
new Job(20, new \DateTime('2003-01-01'), new \DateTime('2010-01-01'), 'A'), new Job(20, new \DateTime('2003-01-01'), new \DateTime('2010-01-01'), 'A'),
new Job(50, new \DateTime('2001-01-01'), new \DateTime('2002-01-01'), 'B'), new Job(50, new \DateTime('2001-01-01'), new \DateTime('2002-01-01'), 'B'),
new Job(10, new \DateTime('2000-01-01'), null, '0'),
new Job(100, new \DateTime('2006-01-01'), new \DateTime('2019-01-01'), 'C'), new Job(100, new \DateTime('2006-01-01'), new \DateTime('2019-01-01'), 'C'),
new Job(200, new \DateTime('2002-01-01'), new \DateTime('2020-01-01'), 'D'), new Job(200, new \DateTime('2002-01-01'), new \DateTime('2020-01-01'), 'D'),
new Job(300, new \DateTime('2004-01-01'), null, '1'), new Job(300, new \DateTime('2004-01-01'), null, '1'),

View File

@ -17,6 +17,7 @@ namespace phpOMS\tests\Algorithm\PathFinding;
use phpOMS\Algorithm\PathFinding\AStar; use phpOMS\Algorithm\PathFinding\AStar;
use phpOMS\Algorithm\PathFinding\AStarNode; use phpOMS\Algorithm\PathFinding\AStarNode;
use phpOMS\Algorithm\PathFinding\Grid; use phpOMS\Algorithm\PathFinding\Grid;
use phpOMS\Algorithm\PathFinding\Path;
use phpOMS\Algorithm\PathFinding\HeuristicType; use phpOMS\Algorithm\PathFinding\HeuristicType;
use phpOMS\Algorithm\PathFinding\MovementType; use phpOMS\Algorithm\PathFinding\MovementType;
@ -249,4 +250,23 @@ class AStarTest extends \PHPUnit\Framework\TestCase
[0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, ], [0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, ],
], $this->gridArray); ], $this->gridArray);
} }
/**
* @testdox A invalid start or end node returns the grid
* @covers phpOMS\Algorithm\PathFinding\AStar
* @group framework
*/
public function testInvalidStartEndNode() : void
{
$grid = Grid::createGridFromArray($this->gridArray, AStarNode::class);
self::assertEquals(
new Path($grid),
$path = AStar::findPath(
999, 999,
-999, -999,
$grid, HeuristicType::EUCLIDEAN, MovementType::DIAGONAL_NO_OBSTACLE
)
);
}
} }

View File

@ -15,6 +15,7 @@ declare(strict_types=1);
namespace phpOMS\tests\Algorithm\PathFinding; namespace phpOMS\tests\Algorithm\PathFinding;
use phpOMS\Algorithm\PathFinding\Grid; use phpOMS\Algorithm\PathFinding\Grid;
use phpOMS\Algorithm\PathFinding\Path;
use phpOMS\Algorithm\PathFinding\HeuristicType; use phpOMS\Algorithm\PathFinding\HeuristicType;
use phpOMS\Algorithm\PathFinding\JumpPointNode; use phpOMS\Algorithm\PathFinding\JumpPointNode;
use phpOMS\Algorithm\PathFinding\JumpPointSearch; use phpOMS\Algorithm\PathFinding\JumpPointSearch;
@ -249,4 +250,23 @@ class JumpPointSearchTest extends \PHPUnit\Framework\TestCase
[0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, ], [0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, ],
], $this->gridArray); ], $this->gridArray);
} }
/**
* @testdox A invalid start or end node returns the grid
* @covers phpOMS\Algorithm\PathFinding\JumpPointSearch
* @group framework
*/
public function testInvalidStartEndNode() : void
{
$grid = Grid::createGridFromArray($this->gridArray, JumpPointNode::class);
self::assertEquals(
new Path($grid),
$path = JumpPointSearch::findPath(
999, 999,
-999, -999,
$grid, HeuristicType::EUCLIDEAN, MovementType::DIAGONAL_NO_OBSTACLE
)
);
}
} }

View File

@ -38,6 +38,7 @@ class CycleSortTest extends \PHPUnit\Framework\TestCase
new NumericElement(1), new NumericElement(1),
new NumericElement(4), new NumericElement(4),
new NumericElement(2), new NumericElement(2),
new NumericElement(2),
new NumericElement(8), new NumericElement(8),
]; ];
} }
@ -62,11 +63,11 @@ class CycleSortTest extends \PHPUnit\Framework\TestCase
{ {
$newList = CycleSort::sort($this->list); $newList = CycleSort::sort($this->list);
self::assertEquals( self::assertEquals(
[1, 2, 4, 5, 8], [$newList[0]->value, $newList[1]->value, $newList[2]->value, $newList[3]->value, $newList[4]->value,] [1, 2, 2, 4, 5, 8], [$newList[0]->value, $newList[1]->value, $newList[2]->value, $newList[3]->value, $newList[4]->value, $newList[5]->value,]
); );
self::assertEquals( self::assertEquals(
[5, 1, 4, 2, 8], [$this->list[0]->value, $this->list[1]->value, $this->list[2]->value, $this->list[3]->value, $this->list[4]->value,] [5, 1, 4, 2, 2, 8], [$this->list[0]->value, $this->list[1]->value, $this->list[2]->value, $this->list[3]->value, $this->list[4]->value, $this->list[5]->value,]
); );
} }
@ -78,11 +79,11 @@ class CycleSortTest extends \PHPUnit\Framework\TestCase
{ {
$newList = CycleSort::sort($this->list, SortOrder::DESC); $newList = CycleSort::sort($this->list, SortOrder::DESC);
self::assertEquals( self::assertEquals(
[8, 5, 4, 2, 1], [$newList[0]->value, $newList[1]->value, $newList[2]->value, $newList[3]->value, $newList[4]->value,] [8, 5, 4, 2, 2, 1], [$newList[0]->value, $newList[1]->value, $newList[2]->value, $newList[3]->value, $newList[4]->value, $newList[5]->value,]
); );
self::assertEquals( self::assertEquals(
[5, 1, 4, 2, 8], [$this->list[0]->value, $this->list[1]->value, $this->list[2]->value, $this->list[3]->value, $this->list[4]->value,] [5, 1, 4, 2, 2, 8], [$this->list[0]->value, $this->list[1]->value, $this->list[2]->value, $this->list[3]->value, $this->list[4]->value, $this->list[5]->value,]
); );
} }
} }

View File

@ -32,7 +32,7 @@ float $value = 0;
public function compare(SortableInterface $obj, int $order = SortOrder::ASC) : bool public function compare(SortableInterface $obj, int $order = SortOrder::ASC) : bool
{ {
return $order === SortOrder::ASC ? $this->value > $obj->value : $this->value < $obj->value; return $order === SortOrder::ASC ? $this->value >= $obj->value : $this->value <= $obj->value;
} }
public function equals(SortableInterface $obj) : bool public function equals(SortableInterface $obj) : bool

View File

@ -38,6 +38,7 @@ class StoogeSortTest extends \PHPUnit\Framework\TestCase
new NumericElement(1), new NumericElement(1),
new NumericElement(4), new NumericElement(4),
new NumericElement(2), new NumericElement(2),
new NumericElement(2),
new NumericElement(8), new NumericElement(8),
]; ];
} }
@ -62,11 +63,11 @@ class StoogeSortTest extends \PHPUnit\Framework\TestCase
{ {
$newList = StoogeSort::sort($this->list); $newList = StoogeSort::sort($this->list);
self::assertEquals( self::assertEquals(
[1, 2, 4, 5, 8], [$newList[0]->value, $newList[1]->value, $newList[2]->value, $newList[3]->value, $newList[4]->value,] [1, 2, 2, 4, 5, 8], [$newList[0]->value, $newList[1]->value, $newList[2]->value, $newList[3]->value, $newList[4]->value, $newList[5]->value,]
); );
self::assertEquals( self::assertEquals(
[5, 1, 4, 2, 8], [$this->list[0]->value, $this->list[1]->value, $this->list[2]->value, $this->list[3]->value, $this->list[4]->value,] [5, 1, 4, 2, 2, 8], [$this->list[0]->value, $this->list[1]->value, $this->list[2]->value, $this->list[3]->value, $this->list[4]->value, $this->list[5]->value,]
); );
} }
@ -78,11 +79,11 @@ class StoogeSortTest extends \PHPUnit\Framework\TestCase
{ {
$newList = StoogeSort::sort($this->list, SortOrder::DESC); $newList = StoogeSort::sort($this->list, SortOrder::DESC);
self::assertEquals( self::assertEquals(
[8, 5, 4, 2, 1], [$newList[0]->value, $newList[1]->value, $newList[2]->value, $newList[3]->value, $newList[4]->value,] [8, 5, 4, 2, 2, 1], [$newList[0]->value, $newList[1]->value, $newList[2]->value, $newList[3]->value, $newList[4]->value, $newList[5]->value,]
); );
self::assertEquals( self::assertEquals(
[5, 1, 4, 2, 8], [$this->list[0]->value, $this->list[1]->value, $this->list[2]->value, $this->list[3]->value, $this->list[4]->value,] [5, 1, 4, 2, 2, 8], [$this->list[0]->value, $this->list[1]->value, $this->list[2]->value, $this->list[3]->value, $this->list[4]->value, $this->list[5]->value,]
); );
} }
} }

View File

@ -76,10 +76,11 @@ class ApplicationManagerTest extends \PHPUnit\Framework\TestCase
/** /**
* @covers phpOMS\Application\ApplicationManager * @covers phpOMS\Application\ApplicationManager
* @covers phpOMS\Application\InstallerAbstract * @covers phpOMS\Application\InstallerAbstract
* @covers phpOMS\Application\UninstallerAbstract
* @covers phpOMS\Application\StatusAbstract * @covers phpOMS\Application\StatusAbstract
* @group framework * @group framework
*/ */
public function testInstall() : void public function testInstallUninstall() : void
{ {
self::assertTrue($this->appManager->install(__DIR__ . '/Testapp', __DIR__ . '/Apps/Testapp')); self::assertTrue($this->appManager->install(__DIR__ . '/Testapp', __DIR__ . '/Apps/Testapp'));
self::assertTrue(\is_dir(__DIR__ . '/Apps/Testapp')); self::assertTrue(\is_dir(__DIR__ . '/Apps/Testapp'));
@ -89,10 +90,32 @@ class ApplicationManagerTest extends \PHPUnit\Framework\TestCase
self::assertTrue(isset($apps['Testapp'])); self::assertTrue(isset($apps['Testapp']));
$providing = $this->appManager->getProvidingForModule('Navigation'); $providing = $this->appManager->getProvidingForModule('Navigation');
Directory::delete(__DIR__ . '/Apps/Testapp');
self::assertTrue(isset($providing['Testapp'])); self::assertTrue(isset($providing['Testapp']));
self::assertTrue(\in_array('Navigation', $providing['Testapp'])); self::assertTrue(\in_array('Navigation', $providing['Testapp']));
$this->appManager->uninstall(__DIR__ . '/Apps/Testapp');
self::assertFalse(\is_dir(__DIR__ . '/Apps/Testapp'));
}
/**
* @testdox A module can be re-initialized
* @covers phpOMS\Application\ApplicationManager
* @covers phpOMS\Application\InstallerAbstract
* @covers phpOMS\Application\StatusAbstract
* @group framework
*/
public function testReInit() : void
{
Directory::delete(__DIR__ . '/Apps/Testapp');
$this->appManager->install(__DIR__ . '/Testapp', __DIR__ . '/Apps/Testapp');
$this->appManager->reInit(__DIR__ . '/Apps/Testapp');
self::assertEquals($r1 = include __DIR__ . '/Testapp/Admin/Install/Application/Routes.php', $r2 = include __DIR__ . '/Apps/Testapp/Routes.php');
self::assertEquals($h1 = include __DIR__ . '/Testapp/Admin/Install/Application/Hooks.php', $h2 = include __DIR__ . '/Apps/Testapp/Hooks.php');
Directory::delete(__DIR__ . '/Apps/Testapp');
} }
/** /**
@ -105,12 +128,40 @@ class ApplicationManagerTest extends \PHPUnit\Framework\TestCase
self::assertFalse($this->appManager->install(__DIR__, __DIR__)); self::assertFalse($this->appManager->install(__DIR__, __DIR__));
} }
/**
* @covers phpOMS\Application\ApplicationManager
* @group framework
*/
public function testMissingInstallerPath() : void
{
self::assertFalse($this->appManager->install(__DIR__ . '/MissingInstaller', __DIR__ . '/Apps/MissingInstaller'));
}
/** /**
* @covers phpOMS\Application\ApplicationManager * @covers phpOMS\Application\ApplicationManager
* @group framework * @group framework
*/ */
public function testMissingApplicationInfoFile() : void public function testMissingApplicationInfoFile() : void
{ {
self::assertFalse($this->appManager->install(__DIR__, __DIR__ . '/newapp', __DIR__ . '/Apps/newapp')); self::assertFalse($this->appManager->install(__DIR__ . '/MissingInfo', __DIR__ . '/Apps/MissingInfo'));
}
/**
* @covers phpOMS\Application\ApplicationManager
* @group framework
*/
public function testInvalidSourceUninstallPath() : void
{
self::assertFalse($this->appManager->uninstall(__DIR__ . '/invalid', __DIR__));
self::assertFalse($this->appManager->uninstall(__DIR__, __DIR__));
}
/**
* @covers phpOMS\Application\ApplicationManager
* @group framework
*/
public function testMissingUninstallerPath() : void
{
self::assertFalse($this->appManager->uninstall(__DIR__ . '/Apps/MissingInstaller'));
} }
} }

View File

@ -0,0 +1,49 @@
<?php
/**
* Orange Management
*
* PHP Version 8.0
*
* @package tests
* @copyright Dennis Eichhorn
* @license OMS License 1.0
* @version 1.0.0
* @link https://orange-management.org
*/
declare(strict_types=1);
namespace phpOMS\tests\Application;
require_once __DIR__ . '/../Autoloader.php';
use phpOMS\Application\InstallerAbstract;
/**
* @testdox phpOMS\tests\Application\InstallerAbstractTest: Application installer
*
* @internal
*/
class InstallerAbstractTest extends \PHPUnit\Framework\TestCase
{
protected InstallerAbstract $installer;
/**
* {@inheritdoc}
*/
protected function setUp() : void
{
$this->installer = new class() extends InstallerAbstract {
public const PATH = __DIR__ . '/Invalid';
};
}
/**
* @covers phpOMS\Application\InstallerAbstract
* @group framework
*/
public function testInvalidTheme() : void
{
$this->installer::installTheme(__DIR__, 'Invalid');
self::assertFalse(\is_dir(__DIR__ . '/css'));
}
}

View File

@ -0,0 +1 @@
<?php

View File

@ -0,0 +1 @@
{}

View File

@ -0,0 +1,51 @@
<?php
/**
* Orange Management
*
* PHP Version 8.0
*
* @package tests
* @copyright Dennis Eichhorn
* @license OMS License 1.0
* @version 1.0.0
* @link https://orange-management.org
*/
declare(strict_types=1);
namespace phpOMS\tests\Application;
require_once __DIR__ . '/../Autoloader.php';
use phpOMS\Application\StatusAbstract;
/**
* @testdox phpOMS\tests\Application\StatusAbstractTest: Application status
*
* @internal
*/
class StatusAbstractTest extends \PHPUnit\Framework\TestCase
{
protected StatusAbstract $status;
/**
* {@inheritdoc}
*/
protected function setUp() : void
{
$this->status = new class() extends StatusAbstract {
public const PATH = __DIR__ . '/Invalid';
};
}
/**
* @covers phpOMS\Application\StatusAbstract
* @group framework
*/
public function testInvalidAppPathActivation() : void
{
$this->status::activateRoutes();
$this->status::activateHooks();
self::assertFalse(\is_file(__DIR__ . '/Routes.php'));
}
}

View File

@ -4,7 +4,7 @@
* *
* PHP Version 8.0 * PHP Version 8.0
* *
* @package Web\Api\Admin * @package phpOMS\tests\Application\Apps\{APPNAME}\Admin
* @copyright Dennis Eichhorn * @copyright Dennis Eichhorn
* @license OMS License 1.0 * @license OMS License 1.0
* @version 1.0.0 * @version 1.0.0
@ -19,7 +19,7 @@ use phpOMS\Application\InstallerAbstract;
/** /**
* Installer class. * Installer class.
* *
* @package Web\Api\Admin * @package phpOMS\tests\Application\Apps\{APPNAME}\Admin
* @license OMS License 1.0 * @license OMS License 1.0
* @link https://orange-management.org * @link https://orange-management.org
* @since 1.0.0 * @since 1.0.0

View File

@ -4,7 +4,7 @@
* *
* PHP Version 8.0 * PHP Version 8.0
* *
* @package Web\Api\Admin * @package phpOMS\tests\Application\Apps\{APPNAME}\Admin
* @copyright Dennis Eichhorn * @copyright Dennis Eichhorn
* @license OMS License 1.0 * @license OMS License 1.0
* @version 1.0.0 * @version 1.0.0
@ -19,7 +19,7 @@ use phpOMS\Application\StatusAbstract;
/** /**
* Status class. * Status class.
* *
* @package Web\Api\Admin * @package phpOMS\tests\Application\Apps\{APPNAME}\Admin
* @license OMS License 1.0 * @license OMS License 1.0
* @link https://orange-management.org * @link https://orange-management.org
* @since 1.0.0 * @since 1.0.0

View File

@ -0,0 +1,30 @@
<?php
/**
* Orange Management
*
* PHP Version 8.0
*
* @package phpOMS\tests\Application\Apps\{APPNAME}\Admin
* @copyright Dennis Eichhorn
* @license OMS License 1.0
* @version 1.0.0
* @link https://orange-management.org
*/
declare(strict_types=1);
namespace phpOMS\tests\Application\Apps\{APPNAME}\Admin;
use phpOMS\Application\UninstallerAbstract;
/**
* Uninstaller class.
*
* @package phpOMS\tests\Application\Apps\{APPNAME}\Admin
* @license OMS License 1.0
* @link https://orange-management.org
* @since 1.0.0
*/
final class Uninstaller extends UninstallerAbstract
{
public const PATH = __DIR__;
}

View File

@ -26,4 +26,4 @@ use phpOMS\Module\ModuleAbstract;
*/ */
final class Controller extends ModuleAbstract final class Controller extends ModuleAbstract
{ {
} }

View File

@ -1,3 +1 @@
#test { html {}
color: #000;
}

View File

@ -0,0 +1 @@
body {}

View File

@ -17,7 +17,8 @@
"description": "The administration module.", "description": "The administration module.",
"directory": "Admin", "directory": "Admin",
"providing": { "providing": {
"Navigation": "*" "Navigation": "*",
"Invalid": "*"
}, },
"dependencies": [] "dependencies": []
} }

View File

@ -83,7 +83,7 @@ class MetricsTest extends \PHPUnit\Framework\TestCase
} }
/** /**
* @testdox The CLTV can be calculated using the migration model * @testdox The CLTV can be calculated using the migration model
* @group framework * @group framework
*/ */
public function testMigrationModel() : void public function testMigrationModel() : void
@ -101,7 +101,7 @@ class MetricsTest extends \PHPUnit\Framework\TestCase
} }
/** /**
* @testdox The migration model can be used in order to determin which buying/none-buying customer group should receive a mailing * @testdox The migration model can be used in order to determin which buying/none-buying customer group should receive a mailing
* @group framework * @group framework
*/ */
public function testMailingSuccessEstimation() : void public function testMailingSuccessEstimation() : void
@ -116,4 +116,17 @@ class MetricsTest extends \PHPUnit\Framework\TestCase
0.1 0.1
); );
} }
/**
* @testdox The probability of a customer buying can be calculated based on his previous purchase behavior
* @group framework
*/
public function testCustomerActiveProbability() : void
{
$purchases = 10;
$periods = 36; // months
self::assertEqualsWithDelta(0.017, Metrics::customerActiveProbability($purchases, $periods, 24), 0.001);
self::assertEqualsWithDelta(1.0, Metrics::customerActiveProbability($purchases, $periods, 36), 0.001);
}
} }

View File

@ -127,6 +127,29 @@ class FileCacheTest extends \PHPUnit\Framework\TestCase
self::assertEquals('testValAdd', $this->cache->get('addKey')); self::assertEquals('testValAdd', $this->cache->get('addKey'));
} }
public function testExists() : void
{
self::assertTrue($this->cache->add('addKey', 'testValAdd'));
self::assertTrue($this->cache->exists('addKey'));
self::assertFalse($this->cache->exists('invalid'));
}
public function testExpiredExists() : void
{
$this->cache->set('key2', 'testVal2', 2);
\sleep(1);
self::assertTrue($this->cache->exists('key2'));
self::assertFalse($this->cache->exists('key2', 0));
\sleep(3);
self::assertFalse($this->cache->exists('key2'));
}
public function testExistsInvalidStatus() : void
{
TestUtils::setMember($this->cache, 'status', CacheStatus::FAILURE);
self::assertFalse($this->cache->exists('invalid'));
}
public function testGetLike() : void public function testGetLike() : void
{ {
$this->cache->set('key1', 'testVal1'); $this->cache->set('key1', 'testVal1');
@ -134,20 +157,47 @@ class FileCacheTest extends \PHPUnit\Framework\TestCase
self::assertEquals([], \array_diff(['testVal1', 'testVal2'], $this->cache->getLike('key\d'))); self::assertEquals([], \array_diff(['testVal1', 'testVal2'], $this->cache->getLike('key\d')));
} }
public function testExpiredGetLike() : void
{
$this->cache->set('key1', 'testVal1', 2);
$this->cache->set('key2', 'testVal2', 2);
\sleep(1);
self::assertEquals([], \array_diff(['testVal1', 'testVal2'], $this->cache->getLike('key\d')));
self::assertEquals([], $this->cache->getLike('key\d', 0));
\sleep(3);
self::assertEquals([], $this->cache->getLike('key\d'));
}
public function testGetLikeInvalidStatus() : void
{
TestUtils::setMember($this->cache, 'status', CacheStatus::FAILURE);
self::assertEquals([], $this->cache->getLike('key\d'));
}
public function testIncrement() : void public function testIncrement() : void
{ {
$this->cache->set(1, 1); $this->cache->set(1, 1);
$this->cache->increment(1, 2); self::assertTrue($this->cache->increment(1, 2));
self::assertEquals(3, $this->cache->get(1)); self::assertEquals(3, $this->cache->get(1));
} }
public function testInvalidKeyIncrement() : void
{
self::assertFalse($this->cache->increment('invalid', 2));
}
public function testDecrement() : void public function testDecrement() : void
{ {
$this->cache->set(1, 3); $this->cache->set(1, 3);
$this->cache->decrement(1, 2); self::assertTrue($this->cache->decrement(1, 2));
self::assertEquals(1, $this->cache->get(1)); self::assertEquals(1, $this->cache->get(1));
} }
public function testInvalidKeyDecrement() : void
{
self::assertFalse($this->cache->decrement('invalid', 2));
}
public function testRename() : void public function testRename() : void
{ {
$this->cache->set('a', 'testVal1'); $this->cache->set('a', 'testVal1');
@ -163,6 +213,23 @@ class FileCacheTest extends \PHPUnit\Framework\TestCase
self::assertEquals([], $this->cache->getLike('key\d')); self::assertEquals([], $this->cache->getLike('key\d'));
} }
public function testExpiredDelteLike() : void
{
$this->cache->set('key1', 'testVal1', 2);
$this->cache->set('key2', 'testVal2', 2);
\sleep(1);
self::assertTrue($this->cache->deleteLike('key\d', 0));
self::assertEquals([], $this->cache->getLike('key\d'));
}
public function testDeleteLikeInvalidStatus() : void
{
TestUtils::setMember($this->cache, 'status', CacheStatus::FAILURE);
self::assertFalse($this->cache->deleteLike('key\d'));
}
public function testUpdateExpire() : void public function testUpdateExpire() : void
{ {
$this->cache->set('key2', 'testVal2', 1); $this->cache->set('key2', 'testVal2', 1);
@ -222,6 +289,11 @@ class FileCacheTest extends \PHPUnit\Framework\TestCase
self::assertNull($this->cache->get('key4')); self::assertNull($this->cache->get('key4'));
} }
public function testInvalidKeyDelete() : void
{
self::assertTrue($this->cache->delete('invalid'));
}
/** /**
* @testdox The cache correctly handles general cache information * @testdox The cache correctly handles general cache information
* @covers phpOMS\DataStorage\Cache\Connection\FileCache<extended> * @covers phpOMS\DataStorage\Cache\Connection\FileCache<extended>

View File

@ -128,6 +128,28 @@ class MemCachedTest extends \PHPUnit\Framework\TestCase
self::assertEquals('testValAdd', $this->cache->get('addKey')); self::assertEquals('testValAdd', $this->cache->get('addKey'));
} }
public function testExists() : void
{
self::assertTrue($this->cache->add('addKey', 'testValAdd'));
self::assertTrue($this->cache->exists('addKey'));
}
public function testExpiredExists() : void
{
$this->cache->set('key2', 'testVal2', 2);
\sleep(1);
self::assertTrue($this->cache->exists('key2'));
self::assertFalse($this->cache->exists('key2', 0));
\sleep(3);
self::assertFalse($this->cache->exists('key2'));
}
public function testExistsInvalidStatus() : void
{
TestUtils::setMember($this->cache, 'status', CacheStatus::FAILURE);
self::assertFalse($this->cache->exists('invalid'));
}
public function testGetLike() : void public function testGetLike() : void
{ {
$this->cache->set('key1', 'testVal1'); $this->cache->set('key1', 'testVal1');
@ -135,20 +157,47 @@ class MemCachedTest extends \PHPUnit\Framework\TestCase
self::assertEquals(['testVal1', 'testVal2'], $this->cache->getLike('key\d')); self::assertEquals(['testVal1', 'testVal2'], $this->cache->getLike('key\d'));
} }
public function testExpiredGetLike() : void
{
$this->cache->set('key1', 'testVal1', 2);
$this->cache->set('key2', 'testVal2', 2);
\sleep(1);
self::assertEquals([], \array_diff(['testVal1', 'testVal2'], $this->cache->getLike('key\d')));
self::assertEquals([], $this->cache->getLike('key\d', 0));
\sleep(3);
self::assertEquals([], $this->cache->getLike('key\d'));
}
public function testGetLikeInvalidStatus() : void
{
TestUtils::setMember($this->cache, 'status', CacheStatus::FAILURE);
self::assertEquals([], $this->cache->getLike('key\d'));
}
public function testIncrement() : void public function testIncrement() : void
{ {
$this->cache->set(1, 1); $this->cache->set(1, 1);
$this->cache->increment(1, 2); self::assertTrue($this->cache->increment(1, 2));
self::assertEquals(3, $this->cache->get(1)); self::assertEquals(3, $this->cache->get(1));
} }
public function testInvalidKeyIncrement() : void
{
self::assertFalse($this->cache->increment('invalid', 2));
}
public function testDecrement() : void public function testDecrement() : void
{ {
$this->cache->set(1, 3); $this->cache->set(1, 3);
$this->cache->decrement(1, 2); self::assertTrue($this->cache->decrement(1, 2));
self::assertEquals(1, $this->cache->get(1)); self::assertEquals(1, $this->cache->get(1));
} }
public function testInvalidKeyDecrement() : void
{
self::assertFalse($this->cache->decrement('invalid', 2));
}
public function testRename() : void public function testRename() : void
{ {
$this->cache->set('a', 'testVal1'); $this->cache->set('a', 'testVal1');
@ -164,6 +213,12 @@ class MemCachedTest extends \PHPUnit\Framework\TestCase
self::assertEquals([], $this->cache->getLike('key\d')); self::assertEquals([], $this->cache->getLike('key\d'));
} }
public function testDeleteLikeInvalidStatus() : void
{
TestUtils::setMember($this->cache, 'status', CacheStatus::FAILURE);
self::assertFalse($this->cache->deleteLike('key\d'));
}
public function testUpdateExpire() : void public function testUpdateExpire() : void
{ {
$this->cache->set('key2', 'testVal2', 1); $this->cache->set('key2', 'testVal2', 1);
@ -223,6 +278,11 @@ class MemCachedTest extends \PHPUnit\Framework\TestCase
self::assertNull($this->cache->get('key4')); self::assertNull($this->cache->get('key4'));
} }
public function testInvalidKeyDelete() : void
{
self::assertTrue($this->cache->delete('invalid'));
}
/** /**
* @testdox The cache correctly handles general cache information * @testdox The cache correctly handles general cache information
* @covers phpOMS\DataStorage\Cache\Connection\MemCached<extended> * @covers phpOMS\DataStorage\Cache\Connection\MemCached<extended>

View File

@ -78,7 +78,7 @@ final class NullCacheTest extends \PHPUnit\Framework\TestCase
public function testDecrement() : void public function testDecrement() : void
{ {
$this->cache->increment(1, 1); $this->cache->decrement(1, 1);
self::assertNull($this->cache->get(1)); self::assertNull($this->cache->get(1));
} }

View File

@ -124,6 +124,28 @@ class RedisCacheTest extends \PHPUnit\Framework\TestCase
self::assertEquals('testValAdd', $this->cache->get('addKey')); self::assertEquals('testValAdd', $this->cache->get('addKey'));
} }
public function testExists() : void
{
self::assertTrue($this->cache->add('addKey', 'testValAdd'));
self::assertTrue($this->cache->exists('addKey'));
}
public function testExpiredExists() : void
{
$this->cache->set('key2', 'testVal2', 2);
\sleep(1);
self::assertTrue($this->cache->exists('key2'));
self::assertFalse($this->cache->exists('key2', 0));
\sleep(3);
self::assertFalse($this->cache->exists('key2'));
}
public function testExistsInvalidStatus() : void
{
TestUtils::setMember($this->cache, 'status', CacheStatus::FAILURE);
self::assertFalse($this->cache->exists('invalid'));
}
public function testGetLike() : void public function testGetLike() : void
{ {
$this->cache->set('key1', 'testVal1'); $this->cache->set('key1', 'testVal1');
@ -131,20 +153,47 @@ class RedisCacheTest extends \PHPUnit\Framework\TestCase
self::assertEquals(['testVal1', 'testVal2'], $this->cache->getLike('key\d')); self::assertEquals(['testVal1', 'testVal2'], $this->cache->getLike('key\d'));
} }
public function testExpiredGetLike() : void
{
$this->cache->set('key1', 'testVal1', 2);
$this->cache->set('key2', 'testVal2', 2);
\sleep(1);
self::assertEquals([], \array_diff(['testVal1', 'testVal2'], $this->cache->getLike('key\d')));
self::assertEquals([], $this->cache->getLike('key\d', 0));
\sleep(3);
self::assertEquals([], $this->cache->getLike('key\d'));
}
public function testGetLikeInvalidStatus() : void
{
TestUtils::setMember($this->cache, 'status', CacheStatus::FAILURE);
self::assertEquals([], $this->cache->getLike('key\d'));
}
public function testIncrement() : void public function testIncrement() : void
{ {
$this->cache->set(1, 1); $this->cache->set(1, 1);
$this->cache->increment(1, 2); self::assertTrue($this->cache->increment(1, 2));
self::assertEquals(3, $this->cache->get(1)); self::assertEquals(3, $this->cache->get(1));
} }
public function testInvalidKeyIncrement() : void
{
self::assertFalse($this->cache->increment('invalid', 2));
}
public function testDecrement() : void public function testDecrement() : void
{ {
$this->cache->set(1, 3); $this->cache->set(1, 3);
$this->cache->decrement(1, 2); self::assertTrue($this->cache->decrement(1, 2));
self::assertEquals(1, $this->cache->get(1)); self::assertEquals(1, $this->cache->get(1));
} }
public function testInvalidKeyDecrement() : void
{
self::assertFalse($this->cache->decrement('invalid', 2));
}
public function testRename() : void public function testRename() : void
{ {
$this->cache->set('a', 'testVal1'); $this->cache->set('a', 'testVal1');
@ -160,6 +209,12 @@ class RedisCacheTest extends \PHPUnit\Framework\TestCase
self::assertEquals([], $this->cache->getLike('key\d')); self::assertEquals([], $this->cache->getLike('key\d'));
} }
public function testDeleteLikeInvalidStatus() : void
{
TestUtils::setMember($this->cache, 'status', CacheStatus::FAILURE);
self::assertFalse($this->cache->deleteLike('key\d'));
}
public function testUpdateExpire() : void public function testUpdateExpire() : void
{ {
$this->cache->set('key2', 'testVal2', 1); $this->cache->set('key2', 'testVal2', 1);
@ -219,6 +274,11 @@ class RedisCacheTest extends \PHPUnit\Framework\TestCase
self::assertNull($this->cache->get('key4')); self::assertNull($this->cache->get('key4'));
} }
public function testInvalidKeyDelete() : void
{
self::assertTrue($this->cache->delete('invalid'));
}
/** /**
* @testdox The cache correctly handles general cache information * @testdox The cache correctly handles general cache information
* @covers phpOMS\DataStorage\Cache\Connection\RedisCache<extended> * @covers phpOMS\DataStorage\Cache\Connection\RedisCache<extended>

View File

@ -108,29 +108,19 @@ class BuilderTest extends \PHPUnit\Framework\TestCase
);*/ );*/
} }
/**
* @testdox The grammar correctly deletes a table
* @covers phpOMS\DataStorage\Database\Schema\Grammar\MysqlGrammar<extended>
* @group framework
*/
public function testMysqlCreateFromSchema() : void public function testMysqlCreateFromSchema() : void
{ {
Builder::createFromSchema( $query = new Builder($this->con);
\json_decode( $sql = 'DROP TABLE `test`, `test_foreign`;';
\file_get_contents(__DIR__ . '/Grammar/testSchema.json'), true
)['test_foreign'],
$this->con
)->execute();
Builder::createFromSchema( self::assertEquals(
\json_decode( $sql,
\file_get_contents(__DIR__ . '/Grammar/testSchema.json'), true $query->dropTable('test')->dropTable('test_foreign')->toSql()
)['test'], );
$this->con
)->execute();
$table = new Builder($this->con);
$tables = $table->selectTables()->execute()->fetchAll(\PDO::FETCH_COLUMN);
self::assertContains('test', $tables);
self::assertContains('test_foreign', $tables);
$delete = new Builder($this->con);
$delete->dropTable('test')->execute();
$delete->dropTable('test_foreign')->execute();
} }
} }

View File

@ -15,7 +15,7 @@ declare(strict_types=1);
namespace phpOMS\tests\DataStorage\Database\Schema\Grammar; namespace phpOMS\tests\DataStorage\Database\Schema\Grammar;
use phpOMS\DataStorage\Database\Connection\MysqlConnection; use phpOMS\DataStorage\Database\Connection\MysqlConnection;
use phpOMS\DataStorage\Database\Schema\Builder as SchemaBuilder; use phpOMS\DataStorage\Database\Schema\Builder;
use phpOMS\DataStorage\Database\Schema\Grammar\MysqlGrammar; use phpOMS\DataStorage\Database\Schema\Grammar\MysqlGrammar;
use phpOMS\Utils\ArrayUtils; use phpOMS\Utils\ArrayUtils;
use phpOMS\Utils\TestUtils; use phpOMS\Utils\TestUtils;
@ -58,15 +58,15 @@ class MysqlGrammarTest extends \PHPUnit\Framework\TestCase
{ {
$definitions = \json_decode(\file_get_contents(__DIR__ . '/testSchema.json'), true); $definitions = \json_decode(\file_get_contents(__DIR__ . '/testSchema.json'), true);
foreach ($definitions as $definition) { foreach ($definitions as $definition) {
SchemaBuilder::createFromSchema($definition, $this->con)->execute(); Builder::createFromSchema($definition, $this->con)->execute();
} }
$table = new SchemaBuilder($this->con); $table = new Builder($this->con);
$tables = $table->selectTables()->execute()->fetchAll(\PDO::FETCH_COLUMN); $tables = $table->selectTables()->execute()->fetchAll(\PDO::FETCH_COLUMN);
self::assertContains('test', $tables); self::assertContains('test', $tables);
self::assertContains('test_foreign', $tables); self::assertContains('test_foreign', $tables);
$field = new SchemaBuilder($this->con); $field = new Builder($this->con);
$fields = $field->selectFields('test')->execute()->fetchAll(); $fields = $field->selectFields('test')->execute()->fetchAll();
foreach ($definitions['test']['fields'] as $key => $field) { foreach ($definitions['test']['fields'] as $key => $field) {
@ -75,6 +75,11 @@ class MysqlGrammarTest extends \PHPUnit\Framework\TestCase
'Couldn\'t find "' . $key . '" in array' 'Couldn\'t find "' . $key . '" in array'
); );
} }
$delete = new Builder($this->con);
$delete->dropTable('test')
->dropTable('test_foreign')
->execute();
} }
/** /**
@ -84,13 +89,22 @@ class MysqlGrammarTest extends \PHPUnit\Framework\TestCase
*/ */
public function testDelete() : void public function testDelete() : void
{ {
$table = new SchemaBuilder($this->con); $definitions = \json_decode(\file_get_contents(__DIR__ . '/testSchema.json'), true);
foreach ($definitions as $definition) {
Builder::createFromSchema($definition, $this->con)->execute();
}
$table = new Builder($this->con);
$tables = $table->selectTables()->execute()->fetchAll(\PDO::FETCH_COLUMN); $tables = $table->selectTables()->execute()->fetchAll(\PDO::FETCH_COLUMN);
self::assertContains('test', $tables);
self::assertContains('test_foreign', $tables);
$delete = new SchemaBuilder($this->con); $delete = new Builder($this->con);
$delete->dropTable('test')->execute(); $delete->dropTable('test')
$delete->dropTable('test_foreign')->execute(); ->dropTable('test_foreign')
->execute();
$table = new Builder($this->con);
$tables = $table->selectTables()->execute()->fetchAll(); $tables = $table->selectTables()->execute()->fetchAll();
self::assertNotContains('test', $tables); self::assertNotContains('test', $tables);
self::assertNotContains('test_foreign', $tables); self::assertNotContains('test_foreign', $tables);

View File

@ -91,6 +91,16 @@ class L11nManagerTest extends \PHPUnit\Framework\TestCase
self::assertEquals('Test strin&amp;g2', $this->l11nManager->getHtml('en', 'Admin', 'RandomThemeDoesNotMatterAlreadyLoaded', 'Test2')); self::assertEquals('Test strin&amp;g2', $this->l11nManager->getHtml('en', 'Admin', 'RandomThemeDoesNotMatterAlreadyLoaded', 'Test2'));
} }
/**
* @testdox An invalid localization source returns an error string
* @covers phpOMS\Localization\L11nManager
* @group framework
*/
public function testInvalidControllerSource() : void
{
self::assertEquals('ERROR-Key', $this->l11nManager->getText('en', 'InvalidSource', 'RandomThemeDoesNotMatterAlreadyLoaded', 'Key'));
}
/** /**
* @testdox Language data can be loaded from a file * @testdox Language data can be loaded from a file
* @covers phpOMS\Localization\L11nManager * @covers phpOMS\Localization\L11nManager

View File

@ -0,0 +1,32 @@
<?php
/**
* Orange Management
*
* PHP Version 8.0
*
* @package tests
* @copyright Dennis Eichhorn
* @license OMS License 1.0
* @version 1.0.0
* @link https://orange-management.org
*/
declare(strict_types=1);
namespace phpOMS\tests\Math\Statistic\Forecast;
use phpOMS\Math\Statistic\Forecast\Forecasts;
/**
* @internal
*/
class ForecastsTest extends \PHPUnit\Framework\TestCase
{
public function testForecastInterval() : void
{
self::assertEqualsWithDelta(
[519.3, 543.6],
Forecasts::getForecastInteval(531.48, 6.21, 1.96),
0.1
);
}
}

View File

@ -43,7 +43,7 @@ class ModuleAbstractTest extends \PHPUnit\Framework\TestCase
{ {
$this->module = new class() extends ModuleAbstract $this->module = new class() extends ModuleAbstract
{ {
public const PATH = __DIR__ . '/'; public const PATH = __DIR__ . '/Test';
const VERSION = '1.2.3'; const VERSION = '1.2.3';

View File

@ -211,6 +211,18 @@ class ModuleManagerTest extends \PHPUnit\Framework\TestCase
/** /**
* @testdox A module can be re-initialized * @testdox A module can be re-initialized
* @covers phpOMS\Module\ModuleManager * @covers phpOMS\Module\ModuleManager
* @group framework
*/
public function testInvalidModuleReInit() : void
{
$this->moduleManager->reInit('Invalid');
self::assertFalse($this->moduleManager->isActive('Invalid'));
}
/**
* @testdox A module can be re-initialized
* @covers phpOMS\Module\ModuleManager
* @covers phpOMS\Module\InstallerAbstract
* @covers phpOMS\Module\StatusAbstract * @covers phpOMS\Module\StatusAbstract
* @group framework * @group framework
*/ */