diff --git a/Application/InstallerAbstract.php b/Application/InstallerAbstract.php index 59b243ce5..3316bd970 100644 --- a/Application/InstallerAbstract.php +++ b/Application/InstallerAbstract.php @@ -18,6 +18,7 @@ use phpOMS\Config\SettingsInterface; use phpOMS\DataStorage\Database\DatabasePool; use phpOMS\DataStorage\Database\Schema\Builder as SchemaBuilder; use phpOMS\System\File\Local\Directory; +use phpOMS\Autoloader; /** * Installer abstract class. @@ -132,6 +133,11 @@ abstract class InstallerAbstract $classPath = \substr(\realpath(static::PATH) . '/Status', \strlen(\realpath(__DIR__ . '/../../'))); $class = \str_replace('/', '\\', $classPath); + + if (!Autoloader::exists($class)) { + throw new \UnexpectedValueException($class); // @codeCoverageIgnore + } + $class::activate($dbPool, $info); } @@ -150,6 +156,10 @@ abstract class InstallerAbstract $class = \str_replace('/', '\\', $classPath); + if (!Autoloader::exists($class)) { + throw new \UnexpectedValueException($class); // @codeCoverageIgnore + } + $class::clearRoutes(); $class::clearHooks(); diff --git a/DataStorage/Database/Connection/PostgresConnection.php b/DataStorage/Database/Connection/PostgresConnection.php index f4f9d9792..261549791 100644 --- a/DataStorage/Database/Connection/PostgresConnection.php +++ b/DataStorage/Database/Connection/PostgresConnection.php @@ -84,7 +84,6 @@ final class PostgresConnection extends ConnectionAbstract } catch (\PDOException $e) { $this->con = new NullPDO(); $this->status = DatabaseStatus::MISSING_DATABASE; - throw new InvalidConnectionConfigException((string) \json_encode($this->dbdata)); } finally { $this->dbdata['password'] = '****'; } diff --git a/DataStorage/Database/Connection/SqlServerConnection.php b/DataStorage/Database/Connection/SqlServerConnection.php index a579e45f9..cd5705241 100644 --- a/DataStorage/Database/Connection/SqlServerConnection.php +++ b/DataStorage/Database/Connection/SqlServerConnection.php @@ -84,7 +84,6 @@ final class SqlServerConnection extends ConnectionAbstract } catch (\PDOException $e) { $this->con = new NullPDO(); $this->status = DatabaseStatus::MISSING_DATABASE; - throw new InvalidConnectionConfigException((string) \json_encode($this->dbdata)); } finally { $this->dbdata['password'] = '****'; } diff --git a/DataStorage/Database/Query/Builder.php b/DataStorage/Database/Query/Builder.php index b1c6e5b98..647a002ba 100644 --- a/DataStorage/Database/Query/Builder.php +++ b/DataStorage/Database/Query/Builder.php @@ -352,18 +352,6 @@ class Builder extends BuilderAbstract return $this; } - /** - * Creating new. - * - * @return Builder - * - * @since 1.0.0 - */ - public function newQuery() : self - { - return new self($this->connection, $this->isReadOnly); - } - /** * Parsing to sql string. * diff --git a/Message/Http/HttpResponse.php b/Message/Http/HttpResponse.php index 731a803d2..a84506694 100644 --- a/Message/Http/HttpResponse.php +++ b/Message/Http/HttpResponse.php @@ -202,17 +202,19 @@ final class HttpResponse extends ResponseAbstract implements RenderableInterface * * This is helpful in case the output buffering should be stopped for streamed/chunked responses (e.g. large data) * + * @param int $levels Levels to close + * * @return void * * @since 1.0.0 */ - public function endAllOutputBuffering() : void + public function endAllOutputBuffering(int $levels = 0) : void { if (!$this->header->isLocked()) { $this->header->push(); } - $levels = \ob_get_level(); + $levels = $levels === 0 ? \ob_get_level() : $levels; for ($i = 0; $i < $levels; ++$i) { \ob_end_clean(); } diff --git a/Message/Mail/Email.php b/Message/Mail/Email.php index 47e4365db..29b1fd331 100644 --- a/Message/Mail/Email.php +++ b/Message/Mail/Email.php @@ -461,6 +461,14 @@ class Email implements MessageInterface return true; } + public function getFrom() : array + { + return [ + $this->from, + $this->fromName, + ]; + } + /** * Sets message type to html or plain. * @@ -475,6 +483,16 @@ class Email implements MessageInterface $this->contentType = $isHtml ? MimeType::M_HTML : MimeType::M_TEXT; } + public function getContentType() : string + { + return $this->contentType; + } + + public function isHtml() : bool + { + return $this->contentType === MimeType::M_HTML; + } + /** * Add a "To" address. * @@ -903,7 +921,7 @@ class Email implements MessageInterface $bytes = \random_bytes($len); if ($bytes === '') { - $bytes = \hash('sha256', \uniqid((string) \mt_rand(), true), true); + $bytes = \hash('sha256', \uniqid((string) \mt_rand(), true), true); // @codeCoverageIgnore } return \str_replace(['=', '+', '/'], '', \base64_encode(\hash('sha256', $bytes, true))); @@ -1804,7 +1822,7 @@ class Email implements MessageInterface */ public function addStringAttachment( string $string, - string $filename , + string $filename, string $encoding = EncodingType::E_BASE64, string $type = '', string $disposition = 'attachment' @@ -2090,7 +2108,7 @@ class Email implements MessageInterface * * @since 1.0.0 */ - private static function normalizeBreaks($text, $breaktype) : string + private static function normalizeBreaks(string $text, string $breaktype) : string { $text = \str_replace(["\r\n", "\r"], "\n", $text); @@ -2259,7 +2277,7 @@ class Email implements MessageInterface * * @since 1.0.0 */ - public function dkimAdd($headersLine, $subject, $body) : string + public function dkimAdd(string $headersLine, string $subject, string $body) : string { $DKIMsignatureType = 'rsa-sha256'; $DKIMcanonicalization = 'relaxed/simple'; diff --git a/Module/InstallerAbstract.php b/Module/InstallerAbstract.php index 999a1c0f0..0195b685e 100644 --- a/Module/InstallerAbstract.php +++ b/Module/InstallerAbstract.php @@ -18,6 +18,7 @@ use phpOMS\Application\ApplicationInfo; use phpOMS\Config\SettingsInterface; use phpOMS\DataStorage\Database\DatabasePool; use phpOMS\DataStorage\Database\Schema\Builder as SchemaBuilder; +use phpOMS\Autoloader; /** * Installer abstract class. @@ -98,6 +99,11 @@ abstract class InstallerAbstract /** @var StatusAbstract $class */ $class = \str_replace('/', '\\', $classPath); + + if (!Autoloader::exists($class)) { + throw new \UnexpectedValueException($class); // @codeCoverageIgnore + } + $class::activate($dbPool, $info); } @@ -117,6 +123,11 @@ abstract class InstallerAbstract /** @var StatusAbstract $class */ $class = \str_replace('/', '\\', $classPath); + + if (!Autoloader::exists($class)) { + throw new \UnexpectedValueException($class); // @codeCoverageIgnore + } + $class::activateRoutes($info, $appInfo); $class::activateHooks($info, $appInfo); } diff --git a/Module/ModuleAbstract.php b/Module/ModuleAbstract.php index 37000a88a..7e73ee739 100644 --- a/Module/ModuleAbstract.php +++ b/Module/ModuleAbstract.php @@ -249,7 +249,7 @@ abstract class ModuleAbstract * * @param int $account Account id * @param mixed $obj Response object - * @param string $mapper Object mapper + * @param string | \Closure $mapper Object mapper * @param string $trigger Trigger for the event manager * @param string $ip Ip * @@ -257,17 +257,24 @@ abstract class ModuleAbstract * * @since 1.0.0 */ - protected function createModel(int $account, mixed $obj, string $mapper, string $trigger, string $ip) : void + protected function createModel(int $account, mixed $obj, string | \Closure $mapper, string $trigger, string $ip) : void { $trigger = static::NAME . '-' . $trigger . '-create'; $this->app->eventManager->triggerSimilar('PRE:Module:' . $trigger, '', $obj); - $id = $mapper::create($obj); + $id = 0; + + if (\is_string($mapper)) { + $id = $mapper::create($obj); + } else { + $mapper(); + } + $this->app->eventManager->triggerSimilar('POST:Module:' . $trigger, '', [ $account, null, $obj, - StringUtils::intHash($mapper), $trigger, + StringUtils::intHash(\is_string($mapper) ? $mapper : \get_class($mapper)), $trigger, static::NAME, (string) $id, '', @@ -281,7 +288,7 @@ abstract class ModuleAbstract * * @param int $account Account id * @param array $objs Response object - * @param string $mapper Object mapper + * @param string | \Closure $mapper Object mapper * @param string $trigger Trigger for the event manager * @param string $ip Ip * @@ -289,18 +296,25 @@ abstract class ModuleAbstract * * @since 1.0.0 */ - protected function createModels(int $account, array $objs, string $mapper, string $trigger, string $ip) : void + protected function createModels(int $account, array $objs, string | \Closure $mapper, string $trigger, string $ip) : void { $trigger = static::NAME . '-' . $trigger . '-create'; foreach ($objs as $obj) { $this->app->eventManager->triggerSimilar('PRE:Module:' . $trigger, '', $obj); - $id = $mapper::create($obj); + $id = 0; + + if (\is_string($mapper)) { + $id = $mapper::create($obj); + } else { + $mapper(); + } + $this->app->eventManager->triggerSimilar('POST:Module:' . $trigger, '', [ $account, null, $obj, - StringUtils::intHash($mapper), $trigger, + StringUtils::intHash(\is_string($mapper) ? $mapper : \get_class($mapper)), $trigger, static::NAME, (string) $id, '', @@ -316,7 +330,7 @@ abstract class ModuleAbstract * @param int $account Account id * @param mixed $old Response object old * @param mixed $new Response object new - * @param \Closure|string $mapper Object mapper + * @param string | \Closure $mapper Object mapper * @param string $trigger Trigger for the event manager * @param string $ip Ip * @@ -353,7 +367,7 @@ abstract class ModuleAbstract * * @param int $account Account id * @param mixed $obj Response object - * @param string $mapper Object mapper + * @param string | \Closure $mapper Object mapper * @param string $trigger Trigger for the event manager * @param string $ip Ip * @@ -361,17 +375,24 @@ abstract class ModuleAbstract * * @since 1.0.0 */ - protected function deleteModel(int $account, mixed $obj, string $mapper, string $trigger, string $ip) : void + protected function deleteModel(int $account, mixed $obj, string | \Closure $mapper, string $trigger, string $ip) : void { $trigger = static::NAME . '-' . $trigger . '-delete'; $this->app->eventManager->triggerSimilar('PRE:Module:' . $trigger, '', $obj); - $id = $mapper::delete($obj); + $id = 0; + + if (\is_string($mapper)) { + $id = $mapper::delete($obj); + } else { + $mapper(); + } + $this->app->eventManager->triggerSimilar('POST:Module:' . $trigger, '', [ $account, $obj, null, - StringUtils::intHash($mapper), $trigger, + StringUtils::intHash(\is_string($mapper) ? $mapper : \get_class($mapper)), $trigger, static::NAME, (string) $id, '', diff --git a/Module/ModuleManager.php b/Module/ModuleManager.php index 28ba9b0a1..8970d4e1d 100644 --- a/Module/ModuleManager.php +++ b/Module/ModuleManager.php @@ -266,10 +266,6 @@ final class ModuleManager \chdir($this->modulePath); $files = \glob('*', \GLOB_ONLYDIR); - if ($files === false) { - return []; - } - $c = $files === false ? 0 : \count($files); for ($i = 0; $i < $c; ++$i) { $info = $this->loadInfo($files[$i]); @@ -368,14 +364,13 @@ final class ModuleManager try { $info = $this->loadInfo($module); if ($info === null) { - return false; + return false; // @codeCoverageIgnore } $this->deactivateModule($info); return true; } catch (\Exception $e) { - echo $e->getMessage(); return false; // @codeCoverageIgnore } } @@ -421,7 +416,7 @@ final class ModuleManager try { $info = $this->loadInfo($module); if ($info === null) { - return false; + return false; // @codeCoverageIgnore } $this->activateModule($info); @@ -506,7 +501,7 @@ final class ModuleManager try { $info = $this->loadInfo($module); if ($info === null) { - return false; + return false; // @codeCoverageIgnore } $this->installed[$module] = $info; @@ -554,7 +549,7 @@ final class ModuleManager try { $info = $this->loadInfo($module); if ($info === null) { - return false; + return false; // @codeCoverageIgnore } $this->installed[$module] = $info; diff --git a/Module/PackageManager.php b/Module/PackageManager.php index 1ea02d62a..d0d752d79 100644 --- a/Module/PackageManager.php +++ b/Module/PackageManager.php @@ -300,9 +300,9 @@ final class PackageManager if (StringUtils::endsWith($component, '.php')) { $cmd = 'php ' . $path; - } elseif (StringUtils::endsWith($component, '.sh') && OperatingSystem::getSystem() === SystemType::LINUX && \is_executable($path)) { - $cmd = $path; - } elseif (StringUtils::endsWith($component, '.batch') && OperatingSystem::getSystem() === SystemType::WIN && \is_executable($path)) { + } elseif ((StringUtils::endsWith($component, '.sh') && OperatingSystem::getSystem() === SystemType::LINUX && \is_executable($path)) + || (StringUtils::endsWith($component, '.batch') && OperatingSystem::getSystem() === SystemType::WIN && \is_executable($path)) + ) { $cmd = $path; } diff --git a/Module/StatusAbstract.php b/Module/StatusAbstract.php index 56d534116..c7a5ba31f 100644 --- a/Module/StatusAbstract.php +++ b/Module/StatusAbstract.php @@ -73,30 +73,7 @@ abstract class StatusAbstract */ public static function activateRoutes(ModuleInfo $info, ApplicationInfo $appInfo = null) : void { - $directories = new Directory(static::PATH . '/Routes'); - - /** @var Directory|File $child */ - foreach ($directories as $child) { - if ($child instanceof Directory) { - foreach ($child as $file) { - if (!\is_dir(__DIR__ . '/../../' . $child->getName() . '/' . \basename($file->getName(), '.php')) - || ($appInfo !== null && \basename($file->getName(), '.php') !== $appInfo->getInternalName()) - ) { - continue; - } - - self::installRoutesHooks(__DIR__ . '/../../' . $child->getName() . '/' . \basename($file->getName(), '.php') . '/Routes.php', $file->getPath()); - } - } elseif ($child instanceof File) { - if (!\is_dir(__DIR__ . '/../../' . $child->getName()) - || ($appInfo !== null && \basename($child->getName(), '.php') !== $appInfo->getInternalName()) - ) { - continue; - } - - self::installRoutesHooks(__DIR__ . '/../../' . $child->getName() . '/Routes.php', $child->getPath()); - } - } + self::activateRoutesHooks($info, $appInfo, 'Routes'); } /** @@ -153,7 +130,24 @@ abstract class StatusAbstract */ public static function activateHooks(ModuleInfo $info, ApplicationInfo $appInfo = null) : void { - $directories = new Directory(static::PATH . '/Hooks'); + self::activateRoutesHooks($info, $appInfo, 'Hooks'); + } + + /** + * Init routes and hooks. + * + * @param ModuleInfo $info Module info + * @param null|ApplicationInfo $appInfo Application info + * + * @return void + * + * @throws PermissionException + * + * @since 1.0.0 + */ + public static function activateRoutesHooks(ModuleInfo $info, ApplicationInfo $appInfo = null, string $type) : void + { + $directories = new Directory(static::PATH . '/' . $type); /** @var Directory|File $child */ foreach ($directories as $child) { @@ -165,7 +159,7 @@ abstract class StatusAbstract continue; } - self::installRoutesHooks(__DIR__ . '/../../' . $child->getName() . '/' . \basename($file->getName(), '.php') . '/Hooks.php', $file->getPath()); + self::installRoutesHooks(__DIR__ . '/../../' . $child->getName() . '/' . \basename($file->getName(), '.php') . '/' . $type . '.php', $file->getPath()); } } elseif ($child instanceof File) { if (!\is_dir(__DIR__ . '/../../' . $child->getName()) @@ -174,7 +168,7 @@ abstract class StatusAbstract continue; } - self::installRoutesHooks(__DIR__ . '/../../' . $child->getName() . '/Hooks.php', $child->getPath()); + self::installRoutesHooks(__DIR__ . '/../../' . $child->getName() . '/' . $type . '.php', $child->getPath()); } } } @@ -207,7 +201,22 @@ abstract class StatusAbstract */ public static function deactivateRoutes(ModuleInfo $info, ApplicationInfo $appInfo = null) : void { - $directories = new Directory(static::PATH . '/Routes'); + self::deactivateRoutesHooks($info, $appInfo, 'Routes'); + } + + /** + * Deactivate routes and hooks. + * + * @param ModuleInfo $info Module info + * @param null|ApplicationInfo $appInfo Application info + * + * @return void + * + * @since 1.0.0 + */ + public static function deactivateRoutesHooks(ModuleInfo $info, ApplicationInfo $appInfo = null, string $type) : void + { + $directories = new Directory(static::PATH . '/'. $type); /** @var Directory|File $child */ foreach ($directories as $child) { @@ -219,7 +228,7 @@ abstract class StatusAbstract continue; } - self::uninstallRoutesHooks(__DIR__ . '/../../' . $child->getName() . '/' . \basename($file->getName(), '.php') . '/Routes.php', $file->getPath()); + self::uninstallRoutesHooks(__DIR__ . '/../../' . $child->getName() . '/' . \basename($file->getName(), '.php') . '/'. $type . '.php', $file->getPath()); } } elseif ($child instanceof File) { if (!\is_dir(__DIR__ . '/../../' . $child->getName()) @@ -228,7 +237,7 @@ abstract class StatusAbstract continue; } - self::uninstallRoutesHooks(__DIR__ . '/../../' . $child->getName() . '/Routes.php', $child->getPath()); + self::uninstallRoutesHooks(__DIR__ . '/../../' . $child->getName() . '/'. $type . '.php', $child->getPath()); } } } @@ -245,7 +254,7 @@ abstract class StatusAbstract * * @since 1.0.0 */ - public static function uninstallRoutesHooks(string $destRoutePath, string $srcRoutePath) : void + protected static function uninstallRoutesHooks(string $destRoutePath, string $srcRoutePath) : void { if (!\is_file($destRoutePath) || !\is_file($srcRoutePath) @@ -283,29 +292,6 @@ abstract class StatusAbstract */ public static function deactivateHooks(ModuleInfo $info, ApplicationInfo $appInfo = null) : void { - $directories = new Directory(static::PATH . '/Hooks'); - - /** @var Directory|File $child */ - foreach ($directories as $child) { - if ($child instanceof Directory) { - foreach ($child as $file) { - if (!\is_dir(__DIR__ . '/../../' . $child->getName() . '/' . \basename($file->getName(), '.php')) - || ($appInfo !== null && \basename($file->getName(), '.php') !== $appInfo->getInternalName()) - ) { - continue; - } - - self::uninstallRoutesHooks(__DIR__ . '/../../' . $child->getName() . '/' . \basename($file->getName(), '.php') . '/Hooks.php', $file->getPath()); - } - } elseif ($child instanceof File) { - if (!\is_dir(__DIR__ . '/../../' . $child->getName()) - || ($appInfo !== null && \basename($child->getName(), '.php') !== $appInfo->getInternalName()) - ) { - continue; - } - - self::uninstallRoutesHooks(__DIR__ . '/../../' . $child->getName() . '/Hooks.php', $child->getPath()); - } - } + self::deactivateRoutesHooks($info, $appInfo, 'Hooks'); } } diff --git a/Stdlib/Graph/Graph.php b/Stdlib/Graph/Graph.php index 16a598ea9..d31b6934b 100644 --- a/Stdlib/Graph/Graph.php +++ b/Stdlib/Graph/Graph.php @@ -529,6 +529,8 @@ class Graph /** * Find all reachable nodes with depth first traversal (iterative) * + * Includes the node itself + * * @param int|string|Node $node1 Graph node * * @return Node[] @@ -548,20 +550,20 @@ class Graph } $visited = []; - $stack = []; - $stack[] = $node1; + $stack = [$node1]; while (!empty($stack)) { - $cNode = \array_pop($stack); - $nodes[] = $cNode; - - if (!isset($visited[$cNode->getId()]) || $visited[$cNode->getId()] === false) { - $visited[$cNode->getId()] = true; + $cNode = \array_pop($stack); + if (isset($visited[$cNode->getId()]) && $visited[$cNode->getId()] === true) { + continue; } + $nodes[] = $cNode; + $visited[$cNode->getId()] = true; + $neighbors = $cNode->getNeighbors(); foreach ($neighbors as $neighbor) { - if (!isset($visited[$cNode->getId()]) || $visited[$cNode->getId()] === false) { + if (!isset($visited[$neighbor->getId()]) || $visited[$neighbor->getId()] === false) { $stack[] = $neighbor; } } @@ -596,6 +598,7 @@ class Graph /** * Get all paths between two nodes + * Inclides end node, but not start node in the paths * * @param int|string|Node $node1 Graph node * @param int|string|Node $node2 Graph node @@ -672,16 +675,33 @@ class Graph return []; } + $mostNodes = 0; + $mostNodesCount = 0; foreach ($paths as $key => $path) { $edges[$key] = 0; + $nodeCount = 0; foreach ($path as $node) { + if ($node1->getEdgeByNeighbor($node) === null) { + continue; + } + $edges[$key] += $node1->getEdgeByNeighbor($node)->getWeight(); + ++$nodeCount; + } + + if ($nodeCount > $mostNodesCount) { + $mostNodesCount = $nodeCount; + $mostNodes = $key; } } - \arsort($edges); + if (\array_sum($edges) > 0.0) { + \arsort($edges); - return $paths[\array_key_first($edges)]; + return $paths[\array_key_first($edges)]; + } + + return $paths[$mostNodes]; } /** @@ -711,20 +731,33 @@ class Graph $paths = $this->getAllPathsBetweenNodes($node1, $node2); $edges = []; + $leastNodes = 0; + $leastNodesCount = \PHP_INT_MAX; foreach ($paths as $key => $path) { $edges[$key] = 0; + $nodeCount = 0; foreach ($path as $node) { + if ($node1->getEdgeByNeighbor($node) === null) { + continue; + } + $edges[$key] += $node1->getEdgeByNeighbor($node)->getWeight(); + ++$nodeCount; + } + + if ($nodeCount < $leastNodesCount && $nodeCount > 0) { + $leastNodesCount = $nodeCount; + $leastNodes = $key; } } - if ($edges === []) { - return []; + if (\array_sum($edges) > 0.0) { + \asort($edges); + + return $paths[\array_key_first($edges)]; } - \asort($edges); - - return $paths[\array_key_first($edges)]; + return $paths[$leastNodes]; } /** diff --git a/tests/Application/UninstallerAbstractTest.php b/tests/Application/UninstallerAbstractTest.php new file mode 100644 index 000000000..c6703e13d --- /dev/null +++ b/tests/Application/UninstallerAbstractTest.php @@ -0,0 +1,58 @@ +uninstaller = new class() extends UninstallerAbstract + { + public const PATH = __DIR__ . '/invalid'; + }; + } + + /** + * @covers phpOMS\Application\UninstallerAbstract + * @group framework + */ + public function testMissingDbFileUninstall() : void + { + $this->uninstaller::dropTables( + new DatabasePool(), + new ApplicationInfo(__DIR__) + ); + + self::assertFalse(\file_exists($this->uninstaller::PATH . '/Install/db.json')); + } +} diff --git a/tests/Bootstrap.php b/tests/Bootstrap.php index 289c2f41d..cb4de514e 100644 --- a/tests/Bootstrap.php +++ b/tests/Bootstrap.php @@ -30,6 +30,7 @@ $CONFIG = [ 'password' => 'root', /* db login password */ 'database' => 'oms', /* db name */ 'weight' => 1000, /* db table prefix */ + 'datetimeformat' => 'Y-m-d H:i:s' ], 'insert' => [ 'db' => 'mysql', /* db type */ @@ -39,6 +40,7 @@ $CONFIG = [ 'password' => 'root', /* db login password */ 'database' => 'oms', /* db name */ 'weight' => 1000, /* db table prefix */ + 'datetimeformat' => 'Y-m-d H:i:s' ], 'select' => [ 'db' => 'mysql', /* db type */ @@ -48,6 +50,7 @@ $CONFIG = [ 'password' => 'root', /* db login password */ 'database' => 'oms', /* db name */ 'weight' => 1000, /* db table prefix */ + 'datetimeformat' => 'Y-m-d H:i:s' ], 'update' => [ 'db' => 'mysql', /* db type */ @@ -57,6 +60,7 @@ $CONFIG = [ 'password' => 'root', /* db login password */ 'database' => 'oms', /* db name */ 'weight' => 1000, /* db table prefix */ + 'datetimeformat' => 'Y-m-d H:i:s' ], 'delete' => [ 'db' => 'mysql', /* db type */ @@ -66,6 +70,7 @@ $CONFIG = [ 'password' => 'root', /* db login password */ 'database' => 'oms', /* db name */ 'weight' => 1000, /* db table prefix */ + 'datetimeformat' => 'Y-m-d H:i:s' ], 'schema' => [ 'db' => 'mysql', /* db type */ @@ -75,6 +80,7 @@ $CONFIG = [ 'password' => 'root', /* db login password */ 'database' => 'oms', /* db name */ 'weight' => 1000, /* db table prefix */ + 'datetimeformat' => 'Y-m-d H:i:s' ], ], 'postgresql' => [ @@ -86,6 +92,7 @@ $CONFIG = [ 'password' => 'root', /* db login password */ 'database' => 'oms', /* db name */ 'weight' => 1000, /* db table prefix */ + 'datetimeformat' => 'Y-m-d H:i:s' ], 'insert' => [ 'db' => 'pgsql', /* db type */ @@ -95,6 +102,7 @@ $CONFIG = [ 'password' => 'root', /* db login password */ 'database' => 'oms', /* db name */ 'weight' => 1000, /* db table prefix */ + 'datetimeformat' => 'Y-m-d H:i:s' ], 'select' => [ 'db' => 'pgsql', /* db type */ @@ -104,6 +112,7 @@ $CONFIG = [ 'password' => 'root', /* db login password */ 'database' => 'oms', /* db name */ 'weight' => 1000, /* db table prefix */ + 'datetimeformat' => 'Y-m-d H:i:s' ], 'update' => [ 'db' => 'pgsql', /* db type */ @@ -113,6 +122,7 @@ $CONFIG = [ 'password' => 'root', /* db login password */ 'database' => 'oms', /* db name */ 'weight' => 1000, /* db table prefix */ + 'datetimeformat' => 'Y-m-d H:i:s' ], 'delete' => [ 'db' => 'pgsql', /* db type */ @@ -122,6 +132,7 @@ $CONFIG = [ 'password' => 'root', /* db login password */ 'database' => 'oms', /* db name */ 'weight' => 1000, /* db table prefix */ + 'datetimeformat' => 'Y-m-d H:i:s' ], 'schema' => [ 'db' => 'pgsql', /* db type */ @@ -131,6 +142,7 @@ $CONFIG = [ 'password' => 'root', /* db login password */ 'database' => 'oms', /* db name */ 'weight' => 1000, /* db table prefix */ + 'datetimeformat' => 'Y-m-d H:i:s' ], ], 'sqlite' => [ @@ -138,31 +150,37 @@ $CONFIG = [ 'db' => 'sqlite', /* db type */ 'database' => __DIR__ . '/test.sqlite', /* db name */ 'weight' => 1000, /* db table prefix */ + 'datetimeformat' => 'Y-m-d H:i:s' ], 'insert' => [ 'db' => 'sqlite', /* db type */ 'database' => __DIR__ . '/test.sqlite', /* db name */ 'weight' => 1000, /* db table prefix */ + 'datetimeformat' => 'Y-m-d H:i:s' ], 'select' => [ 'db' => 'sqlite', /* db type */ 'database' => __DIR__ . '/test.sqlite', /* db name */ 'weight' => 1000, /* db table prefix */ + 'datetimeformat' => 'Y-m-d H:i:s' ], 'update' => [ 'db' => 'sqlite', /* db type */ 'database' => __DIR__ . '/test.sqlite', /* db name */ 'weight' => 1000, /* db table prefix */ + 'datetimeformat' => 'Y-m-d H:i:s' ], 'delete' => [ 'db' => 'sqlite', /* db type */ 'database' => __DIR__ . '/test.sqlite', /* db name */ 'weight' => 1000, /* db table prefix */ + 'datetimeformat' => 'Y-m-d H:i:s' ], 'schema' => [ 'db' => 'sqlite', /* db type */ 'database' => __DIR__ . '/test.sqlite', /* db name */ 'weight' => 1000, /* db table prefix */ + 'datetimeformat' => 'Y-m-d H:i:s' ], ], 'mssql' => [ @@ -174,6 +192,7 @@ $CONFIG = [ 'password' => 'R00troot', /* db login password */ 'database' => 'oms', /* db name */ 'weight' => 1000, /* db table prefix */ + 'datetimeformat' => 'Y-m-d H:i:s' ], 'insert' => [ 'db' => 'mssql', /* db type */ @@ -183,6 +202,7 @@ $CONFIG = [ 'password' => 'R00troot', /* db login password */ 'database' => 'oms', /* db name */ 'weight' => 1000, /* db table prefix */ + 'datetimeformat' => 'Y-m-d H:i:s' ], 'select' => [ 'db' => 'mssql', /* db type */ @@ -192,6 +212,7 @@ $CONFIG = [ 'password' => 'R00troot', /* db login password */ 'database' => 'oms', /* db name */ 'weight' => 1000, /* db table prefix */ + 'datetimeformat' => 'Y-m-d H:i:s' ], 'update' => [ 'db' => 'mssql', /* db type */ @@ -201,6 +222,7 @@ $CONFIG = [ 'password' => 'R00troot', /* db login password */ 'database' => 'oms', /* db name */ 'weight' => 1000, /* db table prefix */ + 'datetimeformat' => 'Y-m-d H:i:s' ], 'delete' => [ 'db' => 'mssql', /* db type */ @@ -210,6 +232,7 @@ $CONFIG = [ 'password' => 'R00troot', /* db login password */ 'database' => 'oms', /* db name */ 'weight' => 1000, /* db table prefix */ + 'datetimeformat' => 'Y-m-d H:i:s' ], 'schema' => [ 'db' => 'mssql', /* db type */ @@ -219,6 +242,7 @@ $CONFIG = [ 'password' => 'R00troot', /* db login password */ 'database' => 'oms', /* db name */ 'weight' => 1000, /* db table prefix */ + 'datetimeformat' => 'Y-m-d H:i:s' ], ], ], diff --git a/tests/DataStorage/Database/Connection/PostgresConnectionTest.php b/tests/DataStorage/Database/Connection/PostgresConnectionTest.php index 352c9eef1..3a47f9640 100644 --- a/tests/DataStorage/Database/Connection/PostgresConnectionTest.php +++ b/tests/DataStorage/Database/Connection/PostgresConnectionTest.php @@ -148,4 +148,19 @@ class PostgresConnectionTest extends \PHPUnit\Framework\TestCase $psql->connect(); self::assertEquals(DatabaseStatus::FAILURE, $psql->getStatus()); } + + /** + * @testdox A invalid database returns a failure + * @covers phpOMS\DataStorage\Database\Connection\PostgresConnection + * @group framework + */ + public function testInvalidDatabaseName() : void + { + $db = $GLOBALS['CONFIG']['db']['core']['masters']['admin']; + $db['database'] = 'invalid'; + + $mysql = new PostgresConnection($db); + $mysql->connect(); + self::assertEquals(DatabaseStatus::MISSING_DATABASE, $mysql->getStatus()); + } } diff --git a/tests/DataStorage/Database/Connection/SQLiteConnectionTest.php b/tests/DataStorage/Database/Connection/SQLiteConnectionTest.php index c2566461c..0b9fb1b21 100644 --- a/tests/DataStorage/Database/Connection/SQLiteConnectionTest.php +++ b/tests/DataStorage/Database/Connection/SQLiteConnectionTest.php @@ -76,6 +76,21 @@ class SQLiteConnectionTest extends \PHPUnit\Framework\TestCase self::assertEquals(DatabaseStatus::FAILURE, $sqlite->getStatus()); } + /** + * @testdox A invalid database returns a failure + * @covers phpOMS\DataStorage\Database\Connection\SQLiteConnection + * @group framework + */ + public function testInvalidDatabaseName() : void + { + $db = $GLOBALS['CONFIG']['db']['core']['masters']['admin']; + $db['database'] = 'invalid'; + + $mysql = new SQLiteConnection($db); + $mysql->connect(); + self::assertEquals(DatabaseStatus::MISSING_DATABASE, $mysql->getStatus()); + } + public static function tearDownAfterClass() : void { if (\is_file($GLOBALS['CONFIG']['db']['core']['sqlite']['admin']['database'])) { diff --git a/tests/DataStorage/Database/DataMapperAbstractTest.php b/tests/DataStorage/Database/DataMapperAbstractTest.php index f21a0e695..3bec916e2 100644 --- a/tests/DataStorage/Database/DataMapperAbstractTest.php +++ b/tests/DataStorage/Database/DataMapperAbstractTest.php @@ -14,10 +14,13 @@ declare(strict_types=1); namespace phpOMS\tests\DataStorage\Database; use phpOMS\tests\DataStorage\Database\TestModel\BaseModel; +use phpOMS\tests\DataStorage\Database\TestModel\NullBaseModel; use phpOMS\tests\DataStorage\Database\TestModel\BaseModelMapper; use phpOMS\tests\DataStorage\Database\TestModel\Conditional; use phpOMS\tests\DataStorage\Database\TestModel\ConditionalMapper; use phpOMS\tests\DataStorage\Database\TestModel\ManyToManyDirectModelMapper; +use phpOMS\tests\DataStorage\Database\TestModel\ManyToManyRelModel; +use phpOMS\tests\DataStorage\Database\TestModel\ManyToManyRelModelMapper; /** * @testdox phpOMS\tests\DataStorage\Database\DataMapperAbstractTest: Datamapper for database models @@ -158,6 +161,7 @@ class DataMapperAbstractTest extends \PHPUnit\Framework\TestCase protected function tearDown() : void { + BaseModelMapper::clearCache(); $GLOBALS['dbpool']->get()->con->prepare('DROP TABLE test_conditional')->execute(); $GLOBALS['dbpool']->get()->con->prepare('DROP TABLE test_base')->execute(); $GLOBALS['dbpool']->get()->con->prepare('DROP TABLE test_belongs_to_one')->execute(); @@ -187,7 +191,24 @@ class DataMapperAbstractTest extends \PHPUnit\Framework\TestCase public function testCreate() : void { self::assertGreaterThan(0, BaseModelMapper::create($this->model)); - self::assertGreaterThan(0, $this->model->id); + self::assertGreaterThan(0, $this->model->getId()); + } + + public function testCreateNullModel() : void + { + $nullModel1 = new NullBaseModel(); + self::assertEquals(null, BaseModelMapper::create($nullModel1)); + + $nullModel2 = new NullBaseModel(77); + self::assertEquals(77, BaseModelMapper::create($nullModel2)); + } + + public function testCreateAlreadyCreatedModel() : void + { + self::assertGreaterThan(0, $id = BaseModelMapper::create($this->model)); + self::assertGreaterThan(0, $this->model->getId()); + self::assertEquals($id, BaseModelMapper::create($this->model)); + self::assertEquals($id, $this->model->getId()); } /** @@ -201,6 +222,23 @@ class DataMapperAbstractTest extends \PHPUnit\Framework\TestCase self::assertGreaterThan(0, $this->modelArray['id']); } + public function testCreateHasManyRelation() : void + { + $id1 = BaseModelMapper::create($this->model); + + $count1 = \count($this->model->hasManyRelations); + + $hasMany = new ManyToManyRelModel(); + $id2 = ManyToManyRelModelMapper::create($hasMany); + + BaseModelMapper::createRelation('hasManyRelations', $id1, $id2); + + BaseModelMapper::clearCache(); + + $base = BaseModelMapper::get($id1); + self::assertCount($count1 + 1, $base->hasManyRelations); + } + /** * @testdox The datamapper successfully returns a database entry as model * @covers phpOMS\DataStorage\Database\DataMapperAbstract @@ -211,7 +249,7 @@ class DataMapperAbstractTest extends \PHPUnit\Framework\TestCase $id = BaseModelMapper::create($this->model); $modelR = BaseModelMapper::get($id); - self::assertEquals($this->model->id, $modelR->id); + self::assertEquals($this->model->getId(), $modelR->getId()); self::assertEquals($this->model->string, $modelR->string); self::assertEquals($this->model->int, $modelR->int); self::assertEquals($this->model->bool, $modelR->bool); @@ -221,8 +259,7 @@ class DataMapperAbstractTest extends \PHPUnit\Framework\TestCase self::assertNull($modelR->datetime_null); /** - * @todo Orange-Management/phpOMS#227 - * Serializable and JsonSerializable data can be inserted and updated in the database but it's not possible to correctly populate a model with the data in its original format. + * @todo Serializable and JsonSerializable data can be inserted and updated in the database but it's not possible to correctly populate a model with the data in its original format. */ //self::assertEquals('123', $modelR->serializable); //self::assertEquals($this->model->json, $modelR->json); @@ -234,15 +271,66 @@ class DataMapperAbstractTest extends \PHPUnit\Framework\TestCase self::assertEquals(\reset($this->model->hasManyRelations)->string, \reset($modelR->hasManyRelations)->string); self::assertEquals($this->model->ownsOneSelf->string, $modelR->ownsOneSelf->string); self::assertEquals($this->model->belongsToOne->string, $modelR->belongsToOne->string); + } + public function testGetAll() : void + { + BaseModelMapper::create($this->model); + self::assertCount(1, BaseModelMapper::getAll()); + } + + public function testGetFor() : void + { + $id = BaseModelMapper::create($this->model); $for = ManyToManyDirectModelMapper::getFor($id, 'to'); self::assertEquals( \reset($this->model->hasManyDirect)->string, $for[1]->string ); + } - self::assertCount(1, BaseModelMapper::getAll()); + public function testGetBy() : void + { + $model1 = new BaseModel(); + $model1->string = '123'; + + $model2 = new BaseModel(); + $model2->string = '456'; + + $id1 = BaseModelMapper::create($model1); + $id2 = BaseModelMapper::create($model2); + + $by = BaseModelMapper::getBy('456', 'string'); + self::assertEquals($model2->getId(), $by->getId()); + } + + public function testGetCached() : void + { + $id = BaseModelMapper::create($this->model); + $modelR = BaseModelMapper::get($id); + $modelR2 = BaseModelMapper::get($id); + + self::assertEquals($modelR->getId(), $modelR2->getId()); + } + + public function testGetNewest() : void + { + $model1 = new BaseModel(); + $model1->datetime = new \DateTime('now'); + $id1 = BaseModelMapper::create($model1); + \sleep(1); + $model2 = new BaseModel(); + $model2->datetime = new \DateTime('now'); + $id2 = BaseModelMapper::create($model2); + + $newest = BaseModelMapper::getNewest(); + self::assertEquals($id2, \reset($newest)->getId()); + } + + public function testGetNullModel() : void + { + self::assertEquals(NullBaseModel::class, \get_class(BaseModelMapper::get(99))); } /** @@ -437,4 +525,18 @@ class DataMapperAbstractTest extends \PHPUnit\Framework\TestCase * Test the deletion of a model with relations (deleting relations). */ } + + public function testDeleteHasManyRelation() : void + { + $id1 = BaseModelMapper::create($this->model); + + $count1 = \count($this->model->hasManyRelations); + + BaseModelMapper::deleteRelation('hasManyRelations', $id1, \reset($this->model->hasManyRelations)->id); + + BaseModelMapper::clearCache(); + $base = BaseModelMapper::get($id1); + + self::assertCount($count1 - 1, $base->hasManyRelations); + } } diff --git a/tests/DataStorage/Database/Schema/Grammar/MysqlGrammarTest.php b/tests/DataStorage/Database/Schema/Grammar/MysqlGrammarTest.php index 30adfba1f..558828a78 100644 --- a/tests/DataStorage/Database/Schema/Grammar/MysqlGrammarTest.php +++ b/tests/DataStorage/Database/Schema/Grammar/MysqlGrammarTest.php @@ -52,6 +52,7 @@ class MysqlGrammarTest extends \PHPUnit\Framework\TestCase /** * @testdox The the grammar correctly creates and returns a database table * @covers phpOMS\DataStorage\Database\Schema\Grammar\MysqlGrammar + * @covers phpOMS\DataStorage\Database\Schema\Builder * @group framework */ public function testSchemaInputOutput() : void diff --git a/tests/DataStorage/Database/TestModel/BaseModel.php b/tests/DataStorage/Database/TestModel/BaseModel.php index 52411a279..de0cee375 100644 --- a/tests/DataStorage/Database/TestModel/BaseModel.php +++ b/tests/DataStorage/Database/TestModel/BaseModel.php @@ -16,7 +16,7 @@ namespace phpOMS\tests\DataStorage\Database\TestModel; class BaseModel { - public $id = 0; + protected $id = 0; public $string = 'Base'; @@ -83,4 +83,9 @@ class BaseModel } }; } + + public function getId() : int + { + return $this->id; + } } diff --git a/tests/DataStorage/Database/TestModel/NullBaseModel.php b/tests/DataStorage/Database/TestModel/NullBaseModel.php index f801c3c51..263947786 100644 --- a/tests/DataStorage/Database/TestModel/NullBaseModel.php +++ b/tests/DataStorage/Database/TestModel/NullBaseModel.php @@ -16,4 +16,8 @@ namespace phpOMS\tests\DataStorage\Database\TestModel; final class NullBaseModel extends BaseModel { + public function __construct(int $id = 0) + { + $this->id = $id; + } } diff --git a/tests/Message/Http/HttpResponseTest.php b/tests/Message/Http/HttpResponseTest.php index a87bf3133..9930dc28f 100644 --- a/tests/Message/Http/HttpResponseTest.php +++ b/tests/Message/Http/HttpResponseTest.php @@ -24,7 +24,7 @@ use phpOMS\System\MimeType; * * @internal */ -class ResponseTest extends \PHPUnit\Framework\TestCase +class HttpResponseTest extends \PHPUnit\Framework\TestCase { protected HttpResponse $response; @@ -87,7 +87,7 @@ class ResponseTest extends \PHPUnit\Framework\TestCase /** * @testdox Test disabling output buffering - * @covers phpOMS\Message\Http\HttpResponse + * @covers phpOMS\Message\Http\HttpResponse * @group framework */ public function testEndAllOutputBuffering() : void @@ -100,9 +100,9 @@ class ResponseTest extends \PHPUnit\Framework\TestCase \ob_start(); \ob_start(); - self::assertEquals($start + 2, \ob_get_level()); - $this->response->endAllOutputBuffering(); - self::assertEquals(0, \ob_get_level()); + self::assertEquals($start + 2, $end = \ob_get_level()); + $this->response->endAllOutputBuffering($end - $start); + self::assertEquals($start, \ob_get_level()); } /** diff --git a/tests/Message/Mail/EmailTest.php b/tests/Message/Mail/EmailTest.php index 2025faecb..826411e53 100644 --- a/tests/Message/Mail/EmailTest.php +++ b/tests/Message/Mail/EmailTest.php @@ -18,6 +18,7 @@ require_once __DIR__ . '/../../Autoloader.php'; use phpOMS\Message\Mail\Email; use phpOMS\System\CharsetType; +use phpOMS\System\MimeType; /** * @testdox phpOMS\tests\Message\MailHandlerTest: Abstract mail handler @@ -46,6 +47,136 @@ class EmailTestTest extends \PHPUnit\Framework\TestCase self::assertFalse($this->mail->hasInlineImage()); } + public function testFromInputOutput() : void + { + self::assertTrue($this->mail->setFrom('test@orange-management.org', 'Test Name')); + self::assertEquals([0 => 'test@orange-management.org', 1 => 'Test Name'], $this->mail->getFrom()); + } + + public function testInvalidFromInputOutput() : void + { + self::assertFalse($this->mail->setFrom('Test Name ')); + self::assertEquals([0 => '', 1 => ''], $this->mail->getFrom()); + } + + public function testContentTypeInputOutput() : void + { + $this->mail->setHtml(true); + self::assertEquals(MimeType::M_HTML, $this->mail->getContentType()); + self::assertTrue($this->mail->isHtml()); + + $this->mail->setHtml(false); + self::assertEquals(MimeType::M_TEXT, $this->mail->getContentType()); + self::assertFalse($this->mail->isHtml()); + } + + public function testAddTo() : void + { + self::assertTrue($this->mail->addTo('test@orange-management.org', 'Test Name')); + self::assertTrue($this->mail->addTo('test2@orange-management.org', 'Test Name 2')); + + self::assertEquals( + [ + 'test@orange-management.org' => ['test@orange-management.org', 'Test Name'], + 'test2@orange-management.org' => ['test2@orange-management.org', 'Test Name 2'], + ], + $this->mail->to + ); + + } + + public function testInvalidAddTo() : void + { + self::assertFalse($this->mail->addTo('test-^invalid', 'Test Name')); + self::assertEquals([], $this->mail->to); + } + + public function testAddCC() : void + { + self::assertTrue($this->mail->addCC('test@orange-management.org', 'Test Name')); + self::assertTrue($this->mail->addCC('test2@orange-management.org', 'Test Name 2')); + + self::assertEquals( + [ + 'test@orange-management.org' => ['test@orange-management.org', 'Test Name'], + 'test2@orange-management.org' => ['test2@orange-management.org', 'Test Name 2'], + ], + $this->mail->cc + ); + + } + + public function testInvalidAddCC() : void + { + self::assertFalse($this->mail->addCC('test-^invalid', 'Test Name')); + self::assertEquals([], $this->mail->cc); + } + + public function testAddBCC() : void + { + self::assertTrue($this->mail->addBCC('test@orange-management.org', 'Test Name')); + self::assertTrue($this->mail->addBCC('test2@orange-management.org', 'Test Name 2')); + + self::assertEquals( + [ + 'test@orange-management.org' => ['test@orange-management.org', 'Test Name'], + 'test2@orange-management.org' => ['test2@orange-management.org', 'Test Name 2'], + ], + $this->mail->bcc + ); + + } + + public function testInvalidAddBCC() : void + { + self::assertFalse($this->mail->addBCC('test-^invalid', 'Test Name')); + self::assertEquals([], $this->mail->bcc); + } + + public function testAddReplyTo() : void + { + self::assertTrue($this->mail->addReplyTo('test@orange-management.org', 'Test Name')); + self::assertTrue($this->mail->addReplyTo('test2@orange-management.org', 'Test Name 2')); + + self::assertEquals( + [ + 'test@orange-management.org' => ['test@orange-management.org', 'Test Name'], + 'test2@orange-management.org' => ['test2@orange-management.org', 'Test Name 2'], + ], + $this->mail->replyTo + ); + + } + + public function testInvalidAddReplyTo() : void + { + self::assertFalse($this->mail->addReplyTo('test-^invalid', 'Test Name')); + self::assertEquals([], $this->mail->replyTo); + } + + public function testMissingAddressPreSend() : void + { + self::assertFalse($this->mail->preSend('')); + } + + public function testAddrFormat() : void + { + self::assertEquals('test@orange-management.org', $this->mail->addrFormat(['test@orange-management.org'])); + self::assertEquals('Test Name ', $this->mail->addrFormat(['test@orange-management.org', 'Test Name'])); + } + + public function testCustomHeaderInputOutput() : void + { + self::assertTrue($this->mail->addCustomHeader('name', 'value')); + self::assertEquals([['name', 'value']], $this->mail->getCustomHeaders()); + } + + public function testInvalidCustomHeaderInputOutput() : void + { + self::assertFalse($this->mail->addCustomHeader('', '')); + self::AssertEquals([], $this->mail->getCustomHeaders()); + } + public function testEmailParsing() : void { self::assertEquals( @@ -53,10 +184,20 @@ class EmailTestTest extends \PHPUnit\Framework\TestCase Email::parseAddresses('Test Name ') ); + self::assertEquals( + [['name' => '', 'address' => 'test@orange-management.org']], + Email::parseAddresses('test@orange-management.org') + ); + self::assertEquals( [['name' => 'Test Name', 'address' => 'test@orange-management.org']], Email::parseAddresses('Test Name ', false) ); + + self::assertEquals( + [['name' => '', 'address' => 'test@orange-management.org']], + Email::parseAddresses('test@orange-management.org', false) + ); } public function testHtml() : void @@ -76,8 +217,58 @@ class EmailTestTest extends \PHPUnit\Framework\TestCase public function testAttachment() : void { - self::assertTrue($this->mail->addAttachment(__DIR__ . '/files/logo.png', 'logo')); + self::assertTrue($this->mail->addAttachment(__DIR__ . '/files/logo.png')); self::assertTrue($this->mail->hasAttachment()); self::assertCount(1, $this->mail->getAttachments()); } + + public function testStringAttachment() : void + { + self::assertTrue($this->mail->addStringAttachment('string', __DIR__ . '/files/logo.png')); + self::assertTrue($this->mail->hasAttachment()); + self::assertCount(1, $this->mail->getAttachments()); + } + + public function testEmbeddedImage() : void + { + self::assertTrue($this->mail->addEmbeddedImage(__DIR__ . '/files/logo.png', 'cid')); + self::assertTrue($this->mail->hasInlineImage()); + self::assertCount(1, $this->mail->getAttachments()); + } + + public function testStringEmbeddedImage() : void + { + self::assertTrue($this->mail->addStringEmbeddedImage('string', 'cid', __DIR__ . '/files/logo.png')); + self::assertTrue($this->mail->hasInlineImage()); + self::assertCount(1, $this->mail->getAttachments()); + } + + public function testInvalidAttachmentPath() : void + { + self::assertFalse($this->mail->addAttachment(__DIR__ . '/invalid.txt')); + } + + public function testInvalidEmbeddedImage() : void + { + self::assertFalse($this->mail->addEmbeddedImage(__DIR__ . '/invalid.png', '')); + } + + public function testQuotedPrintableDkimHeader() : void + { + self::assertEquals( + "J'interdis=20aux=20marchands=20de=20vanter=20trop=20leurs=20marchandises.=20Car=20ils=20se=20font=20vite=20p=C3=A9dagogues=20et=20t'enseignent=20comme=20but=20ce=20qui=20n'est=20par=20essence=20qu'un=20moyen,=20et=20te=20trompant=20ainsi=20sur=20la=20route=20=C3=A0=20suivre=20les=20voil=C3=A0=20bient=C3=B4t=20qui=20te=20d=C3=A9gradent,=20car=20si=20leur=20musique=20est=20vulgaire=20ils=20te=20fabriquent=20pour=20te=20la=20vendre=20une=20=C3=A2me=20vulgaire.", + $this->mail->dkimQP("J'interdis aux marchands de vanter trop leurs marchandises. Car ils se font vite pédagogues et t'enseignent comme but ce qui n'est par essence qu'un moyen, et te trompant ainsi sur la route à suivre les voilà bientôt qui te dégradent, car si leur musique est vulgaire ils te fabriquent pour te la vendre une âme vulgaire.") + ); + } + + public function testCanonicalizedDkimHeader() : void + { + self::assertEquals("header1:value1\r\nheader2:value2", $this->mail->dkimHeaderC("HEADER1:value1\t\nheader2:value2")); + } + + public function testCanonicalizedDkimBody() : void + { + self::assertEquals("Test\r\n string\r\n", $this->mail->dkimBodyC("Test\n string\t")); + self::assertEquals("\r\n", $this->mail->dkimBodyC('')); + } } diff --git a/tests/Message/Mail/MailHandlerTest.php b/tests/Message/Mail/MailHandlerTest.php index 20a4ecf6e..51e34feb4 100644 --- a/tests/Message/Mail/MailHandlerTest.php +++ b/tests/Message/Mail/MailHandlerTest.php @@ -43,7 +43,7 @@ class MailHandlerTest extends \PHPUnit\Framework\TestCase { $this->handler->setMailer(SubmitType::MAIL); - if (!\file_exists($this->handler->mailerTool)) { + if ($this->handler->mailerTool !== '' && !\file_exists(\explode(' ', $this->handler->mailerTool)[0])) { self::markTestSkipped(); } @@ -54,8 +54,12 @@ class MailHandlerTest extends \PHPUnit\Framework\TestCase $mail->addBCC('test3@orange-management.email', 'Dennis Eichhorn'); $mail->addReplyTo('test4@orange-management.email', 'Dennis Eichhorn'); $mail->subject = 'testSendTextWithMail'; - $mail->body = 'This is some content'; + $mail->body = "This is some content\n\Image: \"image\""; + $mail->altBody = 'Alt body'; $mail->addAttachment(__DIR__ . '/files/logo.png', 'logo'); + $mail->addEmbeddedImage(__DIR__ . '/files/logo.png', 'cid1'); + $mail->addStringAttachment('String content', 'string_content_file.txt'); + $mail->addStringEmbeddedImage(\file_get_contents(__DIR__ . '/files/logo.png'), 'cid2'); self::assertTrue($this->handler->send($mail)); } @@ -64,7 +68,7 @@ class MailHandlerTest extends \PHPUnit\Framework\TestCase { $this->handler->setMailer(SubmitType::SENDMAIL); - if (!\file_exists($this->handler->mailerTool)) { + if ($this->handler->mailerTool !== '' && !\file_exists(\explode(' ', $this->handler->mailerTool)[0])) { self::markTestSkipped(); } @@ -75,8 +79,12 @@ class MailHandlerTest extends \PHPUnit\Framework\TestCase $mail->addBCC('test3@orange-management.email', 'Dennis Eichhorn'); $mail->addReplyTo('test4@orange-management.email', 'Dennis Eichhorn'); $mail->subject = 'testSendTextWithSendmail'; - $mail->body = 'This is some content'; + $mail->body = "This is some content\n\Image: \"image\""; + $mail->altBody = 'Alt body'; $mail->addAttachment(__DIR__ . '/files/logo.png', 'logo'); + $mail->addEmbeddedImage(__DIR__ . '/files/logo.png', 'cid1'); + $mail->addStringAttachment('String content', 'string_content_file.txt'); + $mail->addStringEmbeddedImage(\file_get_contents(__DIR__ . '/files/logo.png'), 'cid2'); self::assertTrue($this->handler->send($mail)); } @@ -85,7 +93,7 @@ class MailHandlerTest extends \PHPUnit\Framework\TestCase { $this->handler->setMailer(SubmitType::MAIL); - if (!\file_exists($this->handler->mailerTool)) { + if ($this->handler->mailerTool !== '' && !\file_exists(\explode(' ', $this->handler->mailerTool)[0])) { self::markTestSkipped(); } @@ -101,8 +109,12 @@ class MailHandlerTest extends \PHPUnit\Framework\TestCase $mail->body = ''; $mail->bodyAlt = ''; + $mail->setHtml(true); $mail->msgHTML($message, __DIR__ . '/files'); $mail->addAttachment(__DIR__ . '/files/logo.png', 'logo'); + $mail->addEmbeddedImage(__DIR__ . '/files/logo.png', 'cid1'); + $mail->addStringAttachment('String content', 'string_content_file.txt'); + $mail->addStringEmbeddedImage(\file_get_contents(__DIR__ . '/files/logo.png'), 'cid2'); self::assertTrue($this->handler->send($mail)); } @@ -111,7 +123,7 @@ class MailHandlerTest extends \PHPUnit\Framework\TestCase { $this->handler->setMailer(SubmitType::SENDMAIL); - if (!\file_exists($this->handler->mailerTool)) { + if ($this->handler->mailerTool !== '' && !\file_exists(\explode(' ', $this->handler->mailerTool)[0])) { self::markTestSkipped(); } @@ -127,8 +139,228 @@ class MailHandlerTest extends \PHPUnit\Framework\TestCase $mail->body = ''; $mail->bodyAlt = ''; + $mail->setHtml(true); $mail->msgHTML($message, __DIR__ . '/files'); $mail->addAttachment(__DIR__ . '/files/logo.png', 'logo'); + $mail->addEmbeddedImage(__DIR__ . '/files/logo.png', 'cid1'); + $mail->addStringAttachment('String content', 'string_content_file.txt'); + $mail->addStringEmbeddedImage(\file_get_contents(__DIR__ . '/files/logo.png'), 'cid2'); + + self::assertTrue($this->handler->send($mail)); + } + + public function testSendInlineWithMail() : void + { + $this->handler->setMailer(SubmitType::MAIL); + + if ($this->handler->mailerTool !== '' && !\file_exists(\explode(' ', $this->handler->mailerTool)[0])) { + self::markTestSkipped(); + } + + $mail = new Email(); + $mail->setFrom('test1@orange-management.email', 'Dennis Eichhorn'); + $mail->addTo('test@orange-management.email', 'Dennis Eichhorn'); + $mail->subject = 'testSendInlineWithMail'; + $mail->setHtml(true); + $mail->msgHTML("\"image\""); + $mail->addEmbeddedImage(__DIR__ . '/files/logo.png', 'cid1'); + + self::assertTrue($this->handler->send($mail)); + } + + public function testSendInlineWithSendmail() : void + { + $this->handler->setMailer(SubmitType::SENDMAIL); + + if ($this->handler->mailerTool !== '' && !\file_exists(\explode(' ', $this->handler->mailerTool)[0])) { + self::markTestSkipped(); + } + + $mail = new Email(); + $mail->setFrom('test1@orange-management.email', 'Dennis Eichhorn'); + $mail->addTo('test@orange-management.email', 'Dennis Eichhorn'); + $mail->subject = 'testSendInlineWithSendmail'; + $mail->setHtml(true); + $mail->msgHTML("\"image\""); + $mail->addEmbeddedImage(__DIR__ . '/files/logo.png', 'cid1'); + + self::assertTrue($this->handler->send($mail)); + } + + public function testSendAttachmentWithMail() : void + { + $this->handler->setMailer(SubmitType::MAIL); + + if ($this->handler->mailerTool !== '' && !\file_exists(\explode(' ', $this->handler->mailerTool)[0])) { + self::markTestSkipped(); + } + + $mail = new Email(); + $mail->setFrom('test1@orange-management.email', 'Dennis Eichhorn'); + $mail->addTo('test@orange-management.email', 'Dennis Eichhorn'); + $mail->subject = 'testSendAttachmentWithMail'; + $mail->addAttachment(__DIR__ . '/files/logo.png', 'logo'); + + self::assertTrue($this->handler->send($mail)); + } + + public function testSendAttachmentWithSendmail() : void + { + $this->handler->setMailer(SubmitType::SENDMAIL); + + if ($this->handler->mailerTool !== '' && !\file_exists(\explode(' ', $this->handler->mailerTool)[0])) { + self::markTestSkipped(); + } + + $mail = new Email(); + $mail->setFrom('test1@orange-management.email', 'Dennis Eichhorn'); + $mail->addTo('test@orange-management.email', 'Dennis Eichhorn'); + $mail->subject = 'testSendAttachmentWithSendmail'; + $mail->addAttachment(__DIR__ . '/files/logo.png', 'logo'); + + self::assertTrue($this->handler->send($mail)); + } + + public function testSendAltWithMail() : void + { + $this->handler->setMailer(SubmitType::MAIL); + + if ($this->handler->mailerTool !== '' && !\file_exists(\explode(' ', $this->handler->mailerTool)[0])) { + self::markTestSkipped(); + } + + $mail = new Email(); + $mail->setFrom('test1@orange-management.email', 'Dennis Eichhorn'); + $mail->addTo('test@orange-management.email', 'Dennis Eichhorn'); + $mail->subject = 'testSendAltWithMail'; + $mail->altBody = 'Alt body'; + + self::assertTrue($this->handler->send($mail)); + } + + public function testSendAltWithSendmail() : void + { + $this->handler->setMailer(SubmitType::SENDMAIL); + + if ($this->handler->mailerTool !== '' && !\file_exists(\explode(' ', $this->handler->mailerTool)[0])) { + self::markTestSkipped(); + } + + $mail = new Email(); + $mail->setFrom('test1@orange-management.email', 'Dennis Eichhorn'); + $mail->addTo('test@orange-management.email', 'Dennis Eichhorn'); + $mail->subject = 'testSendAltWithSendmail'; + $mail->altBody = 'Alt body'; + + self::assertTrue($this->handler->send($mail)); + } + + public function testSendAltInlineWithMail() : void + { + $this->handler->setMailer(SubmitType::MAIL); + + if ($this->handler->mailerTool !== '' && !\file_exists(\explode(' ', $this->handler->mailerTool)[0])) { + self::markTestSkipped(); + } + + $mail = new Email(); + $mail->setFrom('test1@orange-management.email', 'Dennis Eichhorn'); + $mail->addTo('test@orange-management.email', 'Dennis Eichhorn'); + $mail->subject = 'testSendAltInlineWithMail'; + $mail->altBody = 'Alt body'; + $mail->setHtml(true); + $mail->msgHTML("\"image\""); + $mail->addEmbeddedImage(__DIR__ . '/files/logo.png', 'cid1'); + + self::assertTrue($this->handler->send($mail)); + } + + public function testSendAltInlineWithSendmail() : void + { + $this->handler->setMailer(SubmitType::SENDMAIL); + + if ($this->handler->mailerTool !== '' && !\file_exists(\explode(' ', $this->handler->mailerTool)[0])) { + self::markTestSkipped(); + } + + $mail = new Email(); + $mail->setFrom('test1@orange-management.email', 'Dennis Eichhorn'); + $mail->addTo('test@orange-management.email', 'Dennis Eichhorn'); + $mail->subject = 'testSendAltInlineWithSendmail'; + $mail->altBody = 'Alt body'; + $mail->setHtml(true); + $mail->msgHTML("\"image\""); + $mail->addEmbeddedImage(__DIR__ . '/files/logo.png', 'cid1'); + + self::assertTrue($this->handler->send($mail)); + } + + public function testSendAltAttachmentWithMail() : void + { + $this->handler->setMailer(SubmitType::MAIL); + + if ($this->handler->mailerTool !== '' && !\file_exists(\explode(' ', $this->handler->mailerTool)[0])) { + self::markTestSkipped(); + } + + $mail = new Email(); + $mail->setFrom('test1@orange-management.email', 'Dennis Eichhorn'); + $mail->addTo('test@orange-management.email', 'Dennis Eichhorn'); + $mail->subject = 'testSendAltAttachmentWithMail'; + $mail->altBody = 'Alt body'; + $mail->addAttachment(__DIR__ . '/files/logo.png', 'logo'); + + self::assertTrue($this->handler->send($mail)); + } + + public function testSendAltAttachmentWithSendmail() : void + { + $this->handler->setMailer(SubmitType::SENDMAIL); + + if ($this->handler->mailerTool !== '' && !\file_exists(\explode(' ', $this->handler->mailerTool)[0])) { + self::markTestSkipped(); + } + + $mail = new Email(); + $mail->setFrom('test1@orange-management.email', 'Dennis Eichhorn'); + $mail->addTo('test@orange-management.email', 'Dennis Eichhorn'); + $mail->subject = 'testSendAltAttachmentWithSendmail'; + $mail->altBody = 'Alt body'; + $mail->addAttachment(__DIR__ . '/files/logo.png', 'logo'); + + self::assertTrue($this->handler->send($mail)); + } + + public function testSendPlainWithMail() : void + { + $this->handler->setMailer(SubmitType::MAIL); + + if ($this->handler->mailerTool !== '' && !\file_exists(\explode(' ', $this->handler->mailerTool)[0])) { + self::markTestSkipped(); + } + + $mail = new Email(); + $mail->setFrom('test1@orange-management.email', 'Dennis Eichhorn'); + $mail->addTo('test@orange-management.email', 'Dennis Eichhorn'); + $mail->subject = 'testSendPlainWithMail'; + $mail->body = 'Body'; + + self::assertTrue($this->handler->send($mail)); + } + + public function testSendPlainWithSendmail() : void + { + $this->handler->setMailer(SubmitType::SENDMAIL); + + if ($this->handler->mailerTool !== '' && !\file_exists(\explode(' ', $this->handler->mailerTool)[0])) { + self::markTestSkipped(); + } + + $mail = new Email(); + $mail->setFrom('test1@orange-management.email', 'Dennis Eichhorn'); + $mail->addTo('test@orange-management.email', 'Dennis Eichhorn'); + $mail->subject = 'testSendPlainWithSendmail'; + $mail->body = 'Body'; self::assertTrue($this->handler->send($mail)); } diff --git a/tests/Message/Mail/files/utf8.html b/tests/Message/Mail/files/utf8.html index d7ea6fda5..caa1cd875 100644 --- a/tests/Message/Mail/files/utf8.html +++ b/tests/Message/Mail/files/utf8.html @@ -18,6 +18,8 @@

Emoji: 😂 🦄 💥 📤 📧

Image data URL (base64)#

Image data URL (URL-encoded)#

+

Image inline: image

+

Image string inline: image

\ No newline at end of file diff --git a/tests/Module/InstallerAbstractTest.php b/tests/Module/InstallerAbstractTest.php new file mode 100644 index 000000000..b1d886cd0 --- /dev/null +++ b/tests/Module/InstallerAbstractTest.php @@ -0,0 +1,58 @@ +installer = new class() extends InstallerAbstract + { + + }; + } + + /** + * @covers phpOMS\Module\InstallerAbstract + * @group framework + */ + public function testInvalidModuleInstall() : void + { + $this->expectException(\UnexpectedValueException::class); + + $this->installer::install( + new DatabasePool(), + new ModuleInfo(__DIR__), + new CoreSettings() + ); + } +} diff --git a/tests/Module/ModuleAbstractTest.php b/tests/Module/ModuleAbstractTest.php index ea2fe2146..fe5d89ce9 100644 --- a/tests/Module/ModuleAbstractTest.php +++ b/tests/Module/ModuleAbstractTest.php @@ -100,7 +100,7 @@ class ModuleAbstractTest extends \PHPUnit\Framework\TestCase $model1 = BaseModelMapper::get(1); $model2 = ManyToManyRelModelMapper::get(1); - $this->createModelRelation(1, $model1->id, $model2->id, BaseModelMapper::class, 'hasManyRelations', '', '127.0.0.1'); + $this->createModelRelation(1, $model1->getId(), $model2->id, BaseModelMapper::class, 'hasManyRelations', '', '127.0.0.1'); } public function deleteRelationDB() : void @@ -108,7 +108,7 @@ class ModuleAbstractTest extends \PHPUnit\Framework\TestCase $model1 = BaseModelMapper::get(1); $model2 = ManyToManyRelModelMapper::get(1); - $this->deleteModelRelation(1, $model1->id, $model2->id, BaseModelMapper::class, 'hasManyRelations', '', '127.0.0.1'); + $this->deleteModelRelation(1, $model1->getId(), $model2->id, BaseModelMapper::class, 'hasManyRelations', '', '127.0.0.1'); } public function creates() : void @@ -134,6 +134,34 @@ class ModuleAbstractTest extends \PHPUnit\Framework\TestCase $model = BaseModelMapper::get(1); $this->deleteModel(1, $model, BaseModelMapper::class, '', '127.0.0.1'); } + + public function createWithCallable() : string + { + \ob_start(); + $this->createModel(1, null, function() { echo 1; }, '', '127.0.0.1'); + return \ob_get_clean(); + } + + public function createsWithCallable() : string + { + \ob_start(); + $this->createModels(1, [null, null], function() { echo 1; }, '', '127.0.0.1'); + return \ob_get_clean(); + } + + public function updateWithCallable() : string + { + \ob_start(); + $this->updateModel(1, null, null, function() { echo 1; }, '', '127.0.0.1'); + return \ob_get_clean(); + } + + public function deleteWithCallable() : string + { + \ob_start(); + $this->deleteModel(1, null, function() { echo 1; }, '', '127.0.0.1'); + return \ob_get_clean(); + } }; } @@ -434,4 +462,19 @@ class ModuleAbstractTest extends \PHPUnit\Framework\TestCase self::assertCount(2, $model->hasManyRelations); $this->dbTeardown(); } + + public function testModelFunctionsWithClosure() : void + { + $output = $this->module->createWithCallable(); + self::assertEquals('1', $output); + + $output = $this->module->createsWithCallable(); + self::assertEquals('11', $output); + + $output = $this->module->updateWithCallable(); + self::assertEquals('1', $output); + + $output = $this->module->deleteWithCallable(); + self::assertEquals('1', $output); + } } diff --git a/tests/Module/ModuleManagerTest.php b/tests/Module/ModuleManagerTest.php index 84143cd91..628b1cc90 100644 --- a/tests/Module/ModuleManagerTest.php +++ b/tests/Module/ModuleManagerTest.php @@ -25,6 +25,7 @@ use phpOMS\Module\ModuleManager; use phpOMS\Module\ModuleStatus; use phpOMS\Router\WebRouter; use phpOMS\Uri\HttpUri; +use phpOMS\Utils\TestUtils; require_once __DIR__ . '/../Autoloader.php'; @@ -261,6 +262,22 @@ class ModuleManagerTest extends \PHPUnit\Framework\TestCase self::assertTrue($this->moduleManager->isRunning('TestModule')); } + public function testGetLanguageForInvalidRequest() : void + { + $request = new HttpRequest(new HttpUri('http://127.0.0.1/en/error/invalid')); + $request->createRequestHashs(0); + + TestUtils::setMember($request, 'hash', ['asdf']); + + self::assertEquals([], $this->moduleManager->getLanguageFiles($request)); + } + + public function testGetActiveModulesWithInvalidBasePath() : void + { + $this->moduleManager = new ModuleManager($this->app, __DIR__ . '/invalid'); + self::assertEquals([], $this->moduleManager->getActiveModules(false)); + } + /** * @testdox Installed modules can be returned * @covers phpOMS\Module\ModuleManager @@ -273,6 +290,21 @@ class ModuleManagerTest extends \PHPUnit\Framework\TestCase self::assertNotEmpty($installed); } + public function testIsInstalled() : void + { + self::assertTrue($this->moduleManager->isInstalled('TestModule')); + } + + public function testInstallingAlreadyInstalledModule() : void + { + self::assertTrue($this->moduleManager->install('TestModule')); + } + + public function testAvailableModules() : void + { + self::assertEquals([], $this->moduleManager->getAvailableModules()); + } + /** * @testdox The valid module can be returned * @covers phpOMS\Module\ModuleManager diff --git a/tests/Module/PackageManagerTest.php b/tests/Module/PackageManagerTest.php index 659bcd5a2..0fa533265 100644 --- a/tests/Module/PackageManagerTest.php +++ b/tests/Module/PackageManagerTest.php @@ -90,6 +90,9 @@ class PackageManagerTest extends \PHPUnit\Framework\TestCase Directory::delete(__DIR__ . '/dummyModule'); } + \chmod(__DIR__ . '/testPackage/testSubPackage/run.batch', 0777); + \chmod(__DIR__ . '/testPackage/testSubPackage/run.sh', 0777); + Directory::copy(__DIR__ . '/testModulePackage', __DIR__ . '/dummyModule'); $package = new PackageManager( diff --git a/tests/Module/StatusAbstractTest.php b/tests/Module/StatusAbstractTest.php new file mode 100644 index 000000000..f53e7dbc6 --- /dev/null +++ b/tests/Module/StatusAbstractTest.php @@ -0,0 +1,40 @@ +status = new class() extends StatusAbstract + { + + }; + } +} diff --git a/tests/Module/UninstallerAbstractTest.php b/tests/Module/UninstallerAbstractTest.php new file mode 100644 index 000000000..408b150b7 --- /dev/null +++ b/tests/Module/UninstallerAbstractTest.php @@ -0,0 +1,58 @@ +uninstaller = new class() extends UninstallerAbstract + { + public const PATH = __DIR__ . '/invalid'; + }; + } + + /** + * @covers phpOMS\Module\UninstallerAbstract + * @group framework + */ + public function testMissingDbFileUninstall() : void + { + $this->uninstaller::dropTables( + new DatabasePool(), + new ModuleInfo(__DIR__) + ); + + self::assertFalse(\file_exists($this->uninstaller::PATH . '/Install/db.json')); + } +} diff --git a/tests/Socket/Client/ClientTest.php b/tests/Socket/Client/ClientTest.php index 543be7210..818b80164 100644 --- a/tests/Socket/Client/ClientTest.php +++ b/tests/Socket/Client/ClientTest.php @@ -64,7 +64,7 @@ class ClientTest extends \PHPUnit\Framework\TestCase $this->app->orgId = 1; $this->app->cachePool = new CachePool($this->app->dbPool); $this->app->accountManager = new AccountManager($GLOBALS['session']); - $this->app->appSettings = new CoreSettings($this->app->dbPool->get()); + $this->app->appSettings = new CoreSettings(); $this->app->moduleManager = new ModuleManager($this->app, __DIR__ . '/../../../../Modules/'); $this->app->dispatcher = new Dispatcher($this->app); $this->app->eventManager = new EventManager($this->app->dispatcher); diff --git a/tests/Socket/Server/ServerTest.php b/tests/Socket/Server/ServerTest.php index 8b312ac45..c3637f610 100644 --- a/tests/Socket/Server/ServerTest.php +++ b/tests/Socket/Server/ServerTest.php @@ -64,7 +64,7 @@ class ServerTest extends \PHPUnit\Framework\TestCase $this->app->orgId = 1; $this->app->cachePool = new CachePool($this->app->dbPool); $this->app->accountManager = new AccountManager($GLOBALS['session']); - $this->app->appSettings = new CoreSettings($this->app->dbPool->get()); + $this->app->appSettings = new CoreSettings(); $this->app->moduleManager = new ModuleManager($this->app, __DIR__ . '/../../../../Modules/'); $this->app->dispatcher = new Dispatcher($this->app); $this->app->eventManager = new EventManager($this->app->dispatcher); diff --git a/tests/Stdlib/Graph/GraphTest.php b/tests/Stdlib/Graph/GraphTest.php index 38734d972..d9ea27b0b 100644 --- a/tests/Stdlib/Graph/GraphTest.php +++ b/tests/Stdlib/Graph/GraphTest.php @@ -63,6 +63,9 @@ class GraphTest extends \PHPUnit\Framework\TestCase self::assertEquals([], $this->graph->getDijkstraShortestPath()); self::assertEquals([], $this->graph->longestPath()); self::assertEquals([], $this->graph->longestPathBetweenNodes('invalid1', 'invalid2')); + self::assertEquals([], $this->graph->shortestPathBetweenNodes('invalid1', 'invalid2')); + self::assertEquals([], $this->graph->getAllPathsBetweenNodes('invalid1', 'invalid2')); + self::assertEquals([], $this->graph->findAllReachableNodesDFS('invalid1')); self::assertEquals(0, $this->graph->getCost()); self::assertEquals($this->graph, $this->graph->getKruskalMinimalSpanningTree()); @@ -393,4 +396,321 @@ class GraphTest extends \PHPUnit\Framework\TestCase self::assertCount(6, $nodes); self::assertEquals(17.0, $minimalSpanningTree->getCost()); } + + /** + * 1 - 3 - 5 + * / |\ / + * 0 | \ / + * \ | \ / + * 2 4 6 + * + * @covers phpOMS\Stdlib\Graph\Graph + * @group framework + */ + public function testFindAllReachableNodesDFS() : void + { + $node0 = new Node('0'); + $node1 = new Node('1'); + $node2 = new Node('2'); + $node3 = new Node('3'); + $node4 = new Node('4'); + $node5 = new Node('5'); + $node6 = new Node('6'); + + $this->graph->setNode($node0); + $this->graph->setNode($node1); + $this->graph->setNode($node2); + $this->graph->setNode($node3); + $this->graph->setNode($node4); + $this->graph->setNode($node5); + $this->graph->setNode($node6); + + $node0->setNodeRelative($node1); + $node0->setNodeRelative($node2); + $node1->setNodeRelative($node2); + $node1->setNodeRelative($node3); + $node1->setNodeRelative($node4); + $node3->setNodeRelative($node5); + $node4->setNodeRelative($node5); + + $nodes = $this->graph->findAllReachableNodesDFS($node0); + self::assertCount(6, $nodes); + } + + /** + * 1 - 3 - 5 + * / |\ / + * 0 | \ / + * \ | \ / + * 2 4 6 + * + * @covers phpOMS\Stdlib\Graph\Graph + * @group framework + */ + public function testGetAllPathsBetweenNodes() : void + { + $node0 = new Node('0'); + $node1 = new Node('1'); + $node2 = new Node('2'); + $node3 = new Node('3'); + $node4 = new Node('4'); + $node5 = new Node('5'); + $node6 = new Node('6'); + + $this->graph->setNode($node0); + $this->graph->setNode($node1); + $this->graph->setNode($node2); + $this->graph->setNode($node3); + $this->graph->setNode($node4); + $this->graph->setNode($node5); + $this->graph->setNode($node6); + + $node0->setNodeRelative($node1); + $node0->setNodeRelative($node2); + $node1->setNodeRelative($node2); + $node1->setNodeRelative($node3); + $node1->setNodeRelative($node4); + $node3->setNodeRelative($node5); + $node4->setNodeRelative($node5); + + $paths = $this->graph->getAllPathsBetweenNodes($node0, $node5); + self::assertCount(4, $paths); + } + + /** + * 1 - 3 - 5 + * / |\ / + * 0 | \ / + * \ | \ / + * 2 4 6 + * + * @covers phpOMS\Stdlib\Graph\Graph + * @group framework + */ + public function testCountAllPathsBetweenNodes() : void + { + $node0 = new Node('0'); + $node1 = new Node('1'); + $node2 = new Node('2'); + $node3 = new Node('3'); + $node4 = new Node('4'); + $node5 = new Node('5'); + $node6 = new Node('6'); + + $this->graph->setNode($node0); + $this->graph->setNode($node1); + $this->graph->setNode($node2); + $this->graph->setNode($node3); + $this->graph->setNode($node4); + $this->graph->setNode($node5); + $this->graph->setNode($node6); + + $node0->setNodeRelative($node1); + $node0->setNodeRelative($node2); + $node1->setNodeRelative($node2); + $node1->setNodeRelative($node3); + $node1->setNodeRelative($node4); + $node3->setNodeRelative($node5); + $node4->setNodeRelative($node5); + + self::assertEquals(4, $this->graph->countAllPathsBetweenNodes($node0, $node5)); + } + + /** + * 1 - 3 - 5 + * / |\ / + * 0 | \ / + * \ | \ / + * 2 4 6 + * + * @covers phpOMS\Stdlib\Graph\Graph + * @group framework + */ + public function testLongestPathBetweenNodes() : void + { + $node0 = new Node('0'); + $node1 = new Node('1'); + $node2 = new Node('2'); + $node3 = new Node('3'); + $node4 = new Node('4'); + $node5 = new Node('5'); + $node6 = new Node('6'); + + $this->graph->setNode($node0); + $this->graph->setNode($node1); + $this->graph->setNode($node2); + $this->graph->setNode($node3); + $this->graph->setNode($node4); + $this->graph->setNode($node5); + $this->graph->setNode($node6); + + $node0->setNodeRelative($node1); + $node0->setNodeRelative($node2); + $node1->setNodeRelative($node2); + $node1->setNodeRelative($node3); + $node1->setNodeRelative($node4); + $node3->setNodeRelative($node5); + $node4->setNodeRelative($node5); + + $path = $this->graph->longestPathBetweenNodes($node0, $node5); + self::assertCount(4, $path); + + $path = $this->graph->longestPathBetweenNodes($node0, $node6); + self::assertEquals([], $path); + } + + /** + * 1 - 3 - 5 + * / |\ / + * 0 | \ / + * \ | \ / + * 2 4 6 + * + * @covers phpOMS\Stdlib\Graph\Graph + * @group framework + */ + public function testShortestPathBetweenNodes() : void + { + $node0 = new Node('0'); + $node1 = new Node('1'); + $node2 = new Node('2'); + $node3 = new Node('3'); + $node4 = new Node('4'); + $node5 = new Node('5'); + $node6 = new Node('6'); + + $this->graph->setNode($node0); + $this->graph->setNode($node1); + $this->graph->setNode($node2); + $this->graph->setNode($node3); + $this->graph->setNode($node4); + $this->graph->setNode($node5); + $this->graph->setNode($node6); + + $node0->setNodeRelative($node1); + $node0->setNodeRelative($node2); + $node1->setNodeRelative($node2); + $node1->setNodeRelative($node3); + $node1->setNodeRelative($node4); + $node3->setNodeRelative($node5); + $node4->setNodeRelative($node5); + + $path = $this->graph->shortestPathBetweenNodes($node0, $node5); + self::assertCount(3, $path); + } + + /** + * 1 - 3 - 5 + * / |\ / + * 0 | \ / + * \ | \ / + * 2 4 6 + * + * @covers phpOMS\Stdlib\Graph\Graph + * @group framework + */ + public function testUnconnectedGraph() : void + { + $node0 = new Node('0'); + $node1 = new Node('1'); + $node2 = new Node('2'); + $node3 = new Node('3'); + $node4 = new Node('4'); + $node5 = new Node('5'); + $node6 = new Node('6'); + + $this->graph->setNode($node0); + $this->graph->setNode($node1); + $this->graph->setNode($node2); + $this->graph->setNode($node3); + $this->graph->setNode($node4); + $this->graph->setNode($node5); + $this->graph->setNode($node6); + + $node0->setNodeRelative($node1); + $node0->setNodeRelative($node2); + $node1->setNodeRelative($node2); + $node1->setNodeRelative($node3); + $node1->setNodeRelative($node4); + $node3->setNodeRelative($node5); + $node4->setNodeRelative($node5); + + self::assertFalse($this->graph->isConnected()); + } + + /** + * 1 - 3 - 5 + * / |\ / + * 0 | \ / + * \ | \ / + * 2 4 + * + * @covers phpOMS\Stdlib\Graph\Graph + * @group framework + */ + public function testConnectedGraph() : void + { + $node0 = new Node('0'); + $node1 = new Node('1'); + $node2 = new Node('2'); + $node3 = new Node('3'); + $node4 = new Node('4'); + $node5 = new Node('5'); + + $this->graph->setNode($node0); + $this->graph->setNode($node1); + $this->graph->setNode($node2); + $this->graph->setNode($node3); + $this->graph->setNode($node4); + $this->graph->setNode($node5); + + $node0->setNodeRelative($node1); + $node0->setNodeRelative($node2); + $node1->setNodeRelative($node2); + $node1->setNodeRelative($node3); + $node1->setNodeRelative($node4); + $node3->setNodeRelative($node5); + $node4->setNodeRelative($node5); + + self::assertTrue($this->graph->isConnected()); + } + + /** + * 1 - 3 - 5 + * / |\ / + * 0 | \ / + * \ | \ / + * 2 4 + * + * @covers phpOMS\Stdlib\Graph\Graph + * @group framework + */ + public function testDiameter() : void + { + self::markTestIncomplete(); + + $node0 = new Node('0'); + $node1 = new Node('1'); + $node2 = new Node('2'); + $node3 = new Node('3'); + $node4 = new Node('4'); + $node5 = new Node('5'); + + $this->graph->setNode($node0); + $this->graph->setNode($node1); + $this->graph->setNode($node2); + $this->graph->setNode($node3); + $this->graph->setNode($node4); + $this->graph->setNode($node5); + + $node0->setNodeRelative($node1); + $node0->setNodeRelative($node2); + $node1->setNodeRelative($node2); + $node1->setNodeRelative($node3); + $node1->setNodeRelative($node4); + $node3->setNodeRelative($node5); + $node4->setNodeRelative($node5); + + self::assertEquals(0, $this->graph->getDiameter()); + } } diff --git a/tests/Stdlib/Graph/NodeTest.php b/tests/Stdlib/Graph/NodeTest.php index 0ef99ae29..d82a63518 100644 --- a/tests/Stdlib/Graph/NodeTest.php +++ b/tests/Stdlib/Graph/NodeTest.php @@ -160,4 +160,20 @@ class NodeTest extends \PHPUnit\Framework\TestCase self::assertCount(2, $node1->getNeighbors()); self::assertCount(1, $node4->getNeighbors()); } + + public function testFindEdgeFromNeighbor() : void + { + $node1 = new Node('A'); + $node2 = new Node('B'); + $node3 = new Node('C'); + $node4 = new Node('D'); + + $node3->setNodeRelative($node4); + + $node1->setNodeRelative($node2); + $node1->setNodeRelative($node3); + + self::assertEquals('C', $node1->getEdgeByNeighbor($node3)->getNode2()->getId()); + self::assertEquals(null, $node1->getEdgeByNeighbor($node4)); + } }