From 3c69c2c209146ff971b1bb6febd82746d901e4d5 Mon Sep 17 00:00:00 2001 From: Dennis Eichhorn Date: Mon, 5 Oct 2020 19:28:57 +0200 Subject: [PATCH] Add tests e.g. preloader --- Application/ApplicationManager.php | 13 +-- Math/Matrix/EigenvalueDecomposition.php | 84 ++++++++++--------- Math/Matrix/LUDecomposition.php | 2 +- Module/PackageManager.php | 2 +- Preloader.php | 2 +- Router/SocketRouter.php | 23 ++++- Router/WebRouter.php | 9 +- Utils/IO/Zip/Tar.php | 5 +- Utils/IO/Zip/Zip.php | 5 +- preload.php | 2 + tests/Application/ApplicationManagerTest.php | 74 ++++++++++++++++ tests/AutoloaderTest.php | 37 ++++++++ .../Matrix/EigenvalueDecompositionTest.php | 24 +++++- tests/Module/PackageManagerTest.php | 2 +- tests/Preload0.php | 27 ++++++ tests/PreloadTest/Preload1.php | 27 ++++++ tests/PreloadTest/Sub/Preload2.php | 27 ++++++ tests/PreloadTest/Sub/Preload3.php | 27 ++++++ tests/PreloaderTest.php | 45 ++++++++++ tests/Router/SocketRouterTest.php | 78 ++++++++++++++--- tests/Router/WebRouterTest.php | 9 -- tests/TestLoad.php | 27 ++++++ tests/TestLoad2.php | 27 ++++++ tests/TestLoad3.php | 27 ++++++ tests/TestLoad4.php | 27 ++++++ 25 files changed, 549 insertions(+), 83 deletions(-) create mode 100644 tests/Application/ApplicationManagerTest.php create mode 100644 tests/Preload0.php create mode 100644 tests/PreloadTest/Preload1.php create mode 100644 tests/PreloadTest/Sub/Preload2.php create mode 100644 tests/PreloadTest/Sub/Preload3.php create mode 100644 tests/PreloaderTest.php create mode 100644 tests/TestLoad.php create mode 100644 tests/TestLoad2.php create mode 100644 tests/TestLoad3.php create mode 100644 tests/TestLoad4.php diff --git a/Application/ApplicationManager.php b/Application/ApplicationManager.php index bf68f7e9c..6bc2b6328 100644 --- a/Application/ApplicationManager.php +++ b/Application/ApplicationManager.php @@ -90,18 +90,18 @@ final class ApplicationManager * @param string $destination Destination of the application * @param string $theme Theme * - * @return void + * @return bool * * @todo Orange-Management/phpOMS#245 * [ApplicationManager] Implement test for invalid source and invalid destination * * @since 1.0.0 */ - public function install(string $source, string $destination, string $theme = 'Default') : void + public function install(string $source, string $destination, string $theme = 'Default') : bool { $destination = \rtrim($destination, '\\/'); if (!\file_exists($source) || \file_exists($destination)) { - return; + return false; } $app = $this->loadInfo(\rtrim($source, '/\\') . '/info.json'); @@ -111,20 +111,21 @@ final class ApplicationManager $this->installTheme($destination, $theme); $this->installFromModules($app); - $files = Directory::list($destination); + $files = Directory::list($destination, '*', true); foreach ($files as $file) { if (!\is_file($destination . '/' . $file)) { continue; } $content = \file_get_contents($destination . '/' . $file); - if ($content === false) { - continue; + continue; // @codeCoverageIgnore } \file_put_contents($destination . '/' . $file, \str_replace('{APPNAME}', \basename($destination), $content)); } + + return true; } /** diff --git a/Math/Matrix/EigenvalueDecomposition.php b/Math/Matrix/EigenvalueDecomposition.php index 8f306402a..95d02f53e 100644 --- a/Math/Matrix/EigenvalueDecomposition.php +++ b/Math/Matrix/EigenvalueDecomposition.php @@ -541,14 +541,14 @@ final class EigenvalueDecomposition --$l; } - if ($l == $n) { + if ($l === $n) { $this->H[$n][$n] = $this->H[$n][$n] + $exshift; $this->D[$n] = $this->H[$n][$n]; $this->E[$n] = 0.0; $iter = 0; --$n; - } elseif ($l == $n - 1) { + } elseif ($l === $n - 1) { $w = $this->H[$n][$n - 1] * $this->H[$n - 1][$n]; $p = ($this->H[$n - 1][$n - 1] - $this->H[$n][$n]) / 2.0; $q = $p * $p + $w; @@ -691,54 +691,56 @@ final class EigenvalueDecomposition $s = $p < 0 ? -\sqrt($p * $p + $q * $q + $r * $r) : \sqrt($p * $p + $q * $q + $r * $r); - if ($s != 0) { - if ($k !== $m) { - $this->H[$k][$k - 1] = -$s * $x; - } elseif ($l !== $m) { - $this->H[$k][$k - 1] = -$this->H[$k][$k - 1]; + if ($s == 0) { + continue; + } + + if ($k !== $m) { + $this->H[$k][$k - 1] = -$s * $x; + } elseif ($l !== $m) { + $this->H[$k][$k - 1] = -$this->H[$k][$k - 1]; + } + + $p += $s; + $x = $p / $s; + $y = $q / $s; + $z = $r / $s; + $q /= $p; + $r /= $p; + + for ($j = $k; $j < $nn; ++$j) { + $p = $this->H[$k][$j] + $q * $this->H[$k + 1][$j]; + if ($notlast) { + $p = $p + $r * $this->H[$k + 2][$j]; + $this->H[$k + 2][$j] = $this->H[$k + 2][$j] - $p * $z; } - $p += $s; - $x = $p / $s; - $y = $q / $s; - $z = $r / $s; - $q /= $p; - $r /= $p; + $this->H[$k][$j] = $this->H[$k][$j] - $p * $x; + $this->H[$k + 1][$j] = $this->H[$k + 1][$j] - $p * $y; + } - for ($j = $k; $j < $nn; ++$j) { - $p = $this->H[$k][$j] + $q * $this->H[$k + 1][$j]; - if ($notlast) { - $p = $p + $r * $this->H[$k + 2][$j]; - $this->H[$k + 2][$j] = $this->H[$k + 2][$j] - $p * $z; - } + $min = \min($n, $k + 3); + for ($i = 0; $i <= $min; ++$i) { + $p = $x * $this->H[$i][$k] + $y * $this->H[$i][$k + 1]; - $this->H[$k][$j] = $this->H[$k][$j] - $p * $x; - $this->H[$k + 1][$j] = $this->H[$k + 1][$j] - $p * $y; + if ($notlast) { + $p = $p + $z * $this->H[$i][$k + 2]; + $this->H[$i][$k + 2] = $this->H[$i][$k + 2] - $p * $r; } - $min = \min($n, $k + 3); - for ($i = 0; $i <= $min; ++$i) { - $p = $x * $this->H[$i][$k] + $y * $this->H[$i][$k + 1]; + $this->H[$i][$k] = $this->H[$i][$k] - $p; + $this->H[$i][$k + 1] = $this->H[$i][$k + 1] - $p * $q; + } - if ($notlast) { - $p = $p + $z * $this->H[$i][$k + 2]; - $this->H[$i][$k + 2] = $this->H[$i][$k + 2] - $p * $r; - } + for ($i = $low; $i <= $high; ++$i) { + $p = $x * $this->V[$i][$k] + $y * $this->V[$i][$k + 1]; - $this->H[$i][$k] = $this->H[$i][$k] - $p; - $this->H[$i][$k + 1] = $this->H[$i][$k + 1] - $p * $q; - } - - for ($i = $low; $i <= $high; ++$i) { - $p = $x * $this->V[$i][$k] + $y * $this->V[$i][$k + 1]; - - if ($notlast) { - $p += $z * $this->V[$i][$k + 2]; - $this->V[$i][$k + 2] = $this->V[$i][$k + 2] - $p * $r; - } - $this->V[$i][$k] = $this->V[$i][$k] - $p; - $this->V[$i][$k + 1] = $this->V[$i][$k + 1] - $p * $q; + if ($notlast) { + $p += $z * $this->V[$i][$k + 2]; + $this->V[$i][$k + 2] = $this->V[$i][$k + 2] - $p * $r; } + $this->V[$i][$k] = $this->V[$i][$k] - $p; + $this->V[$i][$k + 1] = $this->V[$i][$k + 1] - $p * $q; } } } diff --git a/Math/Matrix/LUDecomposition.php b/Math/Matrix/LUDecomposition.php index 07345e6b7..4c9b06530 100644 --- a/Math/Matrix/LUDecomposition.php +++ b/Math/Matrix/LUDecomposition.php @@ -111,7 +111,7 @@ final class LUDecomposition } } - if ($p != $j) { + if ($p !== $j) { for ($k = 0; $k < $this->n; ++$k) { $t = $this->LU[$p][$k]; $this->LU[$p][$k] = $this->LU[$j][$k]; diff --git a/Module/PackageManager.php b/Module/PackageManager.php index 72c43d131..bac88111a 100644 --- a/Module/PackageManager.php +++ b/Module/PackageManager.php @@ -152,7 +152,7 @@ final class PackageManager */ private function hashFiles() : string { - $files = Directory::list($this->extractPath); + $files = Directory::list($this->extractPath, '*', true); $state = \sodium_crypto_generichash_init(); foreach ($files as $file) { diff --git a/Preloader.php b/Preloader.php index a8f83e5d2..89d443779 100644 --- a/Preloader.php +++ b/Preloader.php @@ -108,7 +108,7 @@ final class Preloader $fh = \opendir($path); if ($fh === false) { - return; + return; // @codeCoverageIgnore } while ($file = \readdir($fh)) { diff --git a/Router/SocketRouter.php b/Router/SocketRouter.php index 9768ae703..ae2b5b849 100644 --- a/Router/SocketRouter.php +++ b/Router/SocketRouter.php @@ -77,14 +77,20 @@ final class SocketRouter implements RouterInterface * * @since 1.0.0 */ - public function add(string $route, $destination) : void - { + public function add( + string $route, + $destination, + array $validation = [], + string $dataPattern = '' + ) : void { if (!isset($this->routes[$route])) { $this->routes[$route] = []; } $this->routes[$route][] = [ - 'dest' => $destination, + 'dest' => $destination, + 'validation' => empty($validation) ? null : $validation, + 'pattern' => empty($dataPattern) ? null : $dataPattern, ]; } @@ -136,7 +142,16 @@ final class SocketRouter implements RouterInterface } } - $bound[] = ['dest' => $d['dest']]; + $temp = ['dest' => $d['dest']]; + + // fill data + if (isset($d['pattern'])) { + \preg_match($d['pattern'], $uri, $matches); + + $temp['data'] = $matches; + } + + $bound[] = $temp; } } diff --git a/Router/WebRouter.php b/Router/WebRouter.php index 7934c76e8..e81bf4f97 100644 --- a/Router/WebRouter.php +++ b/Router/WebRouter.php @@ -83,8 +83,13 @@ final class WebRouter implements RouterInterface * * @since 1.0.0 */ - public function add(string $route, $destination, int $verb = RouteVerb::GET, bool $csrf = false, array $validation = [], string $dataPattern = '') : void - { + public function add( + string $route, + $destination, + int $verb = RouteVerb::GET, + bool $csrf = false, array $validation = [], + string $dataPattern = '' + ) : void { if (!isset($this->routes[$route])) { $this->routes[$route] = []; } diff --git a/Utils/IO/Zip/Tar.php b/Utils/IO/Zip/Tar.php index 1dbe70125..3c3c2ba94 100644 --- a/Utils/IO/Zip/Tar.php +++ b/Utils/IO/Zip/Tar.php @@ -42,10 +42,13 @@ class Tar implements ArchiveInterface $tar = new \PharData($destination); /** - * @var string $source * @var string $relative */ foreach ($sources as $source => $relative) { + if (\is_int($source)) { + $source = $relative; + } + if (($source = \realpath($source)) === false || ($source = \str_replace('\\', '/', $source)) === false || !\file_exists($source) diff --git a/Utils/IO/Zip/Zip.php b/Utils/IO/Zip/Zip.php index 92ead5d82..4f9bd28bc 100644 --- a/Utils/IO/Zip/Zip.php +++ b/Utils/IO/Zip/Zip.php @@ -45,10 +45,13 @@ class Zip implements ArchiveInterface } /** - * @var string $source * @var string $relative */ foreach ($sources as $source => $relative) { + if (\is_int($source)) { + $source = $relative; + } + if (($source = \realpath($source)) === false || ($source = \str_replace('\\', '/', $source)) === false || !\file_exists($source) diff --git a/preload.php b/preload.php index 57edae831..d4e4dcf4e 100644 --- a/preload.php +++ b/preload.php @@ -12,6 +12,7 @@ */ declare(strict_types=1); +// @codeCoverageIgnoreStart require_once __DIR__ . '/Preloader.php'; $preloader = new \phpOMS\Preloader(); @@ -35,3 +36,4 @@ $preloader->includePath(__DIR__ . '/Account') ->includePath(__DIR__ . '/Uri') ->includePath(__DIR__ . '/Views') ->load(); +// @codeCoverageIgnoreEnd diff --git a/tests/Application/ApplicationManagerTest.php b/tests/Application/ApplicationManagerTest.php new file mode 100644 index 000000000..8c737f7fd --- /dev/null +++ b/tests/Application/ApplicationManagerTest.php @@ -0,0 +1,74 @@ +appName = 'Api'; + $app->dbPool = $GLOBALS['dbpool']; + $app->router = new WebRouter(); + $app->dispatcher = new Dispatcher($app); + $app->appSettings = new CoreSettings($app->dbPool->get('admin')); + $app->moduleManager = new ModuleManager($app, __DIR__ . '/../../../Modules'); + + $this->appManager = new ApplicationManager($app->moduleManager); + } + + public function testInstall() : void + { + self::markTestIncomplete(); + } + + public function testInvalidSourceDestinationInstallPath() : void + { + self::assertFalse($this->appManager->install(__DIR__ . '/invalid', __DIR__)); + self::assertFalse($this->appManager->install(__DIR__, __DIR__)); + } + + public function testMissingApplicationInfoFile() : void + { + $this->expectException(\phpOMS\System\File\PathException::class); + + self::assertFalse($this->appManager->install(__DIR__, __DIR__ . '/newapp')); + } + + public function testInstallFromModules() : void + { + self::markTestIncomplete(); + } +} diff --git a/tests/AutoloaderTest.php b/tests/AutoloaderTest.php index 2a7efa8da..47f56355e 100644 --- a/tests/AutoloaderTest.php +++ b/tests/AutoloaderTest.php @@ -33,4 +33,41 @@ class AutoloaderTest extends \PHPUnit\Framework\TestCase self::assertTrue(Autoloader::exists('\phpOMS\Autoloader')); self::assertFalse(Autoloader::exists('\Does\Not\Exist')); } + + public function testLoading() : void + { + Autoloader::defaultAutoloader('\phpOMS\tests\TestLoad'); + + $includes = \get_included_files(); + self::assertTrue(\in_array(\realpath(__DIR__ . '/TestLoad.php'), $includes)); + } + + public function testManualPathLoading() : void + { + Autoloader::addPath(__DIR__ . '/../'); + Autoloader::defaultAutoloader('\tests\TestLoad2'); + Autoloader::defaultAutoloader('\tests\Invalid'); + + $includes = \get_included_files(); + self::assertTrue(\in_array(\realpath(__DIR__ . '/TestLoad2.php'), $includes)); + } + + public function testOpcodeCacheInvalidation() : void + { + if (!\extension_loaded('opcache')) { + $this->markTestSkipped( + 'The opcache extension is not available.' + ); + } + + Autoloader::defaultAutoloader('\phpOMS\tests\TestLoad3'); + Autoloader::invalidate(__DIR__ . '/TestLoad3.php'); + self::assertTrue(\opcache_is_script_cached(__DIR__ . '/TestLoad3.php')); + } + + public function testUncachedInvalidation() : void + { + self::assertFalse(\opcache_is_script_cached(__DIR__ . '/TestLoad4.php')); + self::assertFalse(Autoloader::invalidate(__DIR__ . '/TestLoad4.php')); + } } diff --git a/tests/Math/Matrix/EigenvalueDecompositionTest.php b/tests/Math/Matrix/EigenvalueDecompositionTest.php index 675ed5984..ee405ae32 100644 --- a/tests/Math/Matrix/EigenvalueDecompositionTest.php +++ b/tests/Math/Matrix/EigenvalueDecompositionTest.php @@ -70,7 +70,8 @@ class EigenvalueDecompositionTest extends \PHPUnit\Framework\TestCase $eig = new EigenvalueDecomposition($A); - self::assertEqualsWithDelta([0, 2, 5], $eig->getRealEigenvalues()->toArray(), 0.2); + self::assertEqualsWithDelta([0, 2, 5], $eig->getRealEigenvalues()->toArray(), 0.1); + self::assertEqualsWithDelta([0, 0, 0], $eig->getImagEigenvalues()->toArray(), 0.1); } /** @@ -135,7 +136,8 @@ class EigenvalueDecompositionTest extends \PHPUnit\Framework\TestCase $eig = new EigenvalueDecomposition($A); - self::assertEqualsWithDelta([-5, 3, 6], $eig->getRealEigenvalues()->toArray(), 0.2); + self::assertEqualsWithDelta([-5, 3, 6], $eig->getRealEigenvalues()->toArray(), 0.1); + self::assertEqualsWithDelta([0, 0, 0], $eig->getImagEigenvalues()->toArray(), 0.1);; } /** @@ -234,4 +236,22 @@ class EigenvalueDecompositionTest extends \PHPUnit\Framework\TestCase 0.2 ); } + + public function testComplexEigenvalueDecomposition() : void + { + $A = new Matrix(); + $A->setMatrix([ + [3, -2], + [4, -1], + ]); + + $eig = new EigenvalueDecomposition($A); + self::assertEqualsWithDelta([ + [1, 2], + [-2, 1], + ], $eig->getD()->toArray(), 0.1); + + self::assertEqualsWithDelta([1, 1], $eig->getRealEigenvalues()->toArray(), 0.1); + self::assertEqualsWithDelta([2, -2], $eig->getImagEigenvalues()->toArray(), 0.1); + } } diff --git a/tests/Module/PackageManagerTest.php b/tests/Module/PackageManagerTest.php index 63c128d4b..8a6338016 100644 --- a/tests/Module/PackageManagerTest.php +++ b/tests/Module/PackageManagerTest.php @@ -50,7 +50,7 @@ class PackageManagerTest extends \PHPUnit\Framework\TestCase $alice_sign_publickey = \sodium_crypto_sign_publickey($alice_sign_kp); // create signature - $files = Directory::list(__DIR__ . '/testPackage'); + $files = Directory::list(__DIR__ . '/testPackage', '*', true); $state = \sodium_crypto_generichash_init(); foreach ($files as $file) { diff --git a/tests/Preload0.php b/tests/Preload0.php new file mode 100644 index 000000000..463a4aae3 --- /dev/null +++ b/tests/Preload0.php @@ -0,0 +1,27 @@ +ignore(__DIR__ . '/PreloadTest/Sub/Preload3.php') + ->includePath(__DIR__ . '/PreloadTest') + ->includePath(__DIR__ . '/Preload0.php') + ->includePath(__DIR__ . '/PreloadTest/Sub/Preload3.php') + ->load(); + + $includes = \get_included_files(); + self::assertTrue(\in_array(\realpath(__DIR__ . '/PreloadTest/Preload1.php'), $includes)); + self::assertTrue(\in_array(\realpath(__DIR__ . '/PreloadTest/Sub/Preload2.php'), $includes)); + self::assertFalse(\in_array(\realpath(__DIR__ . '/PreloadTest/Sub/Preload3.php'), $includes)); + } +} diff --git a/tests/Router/SocketRouterTest.php b/tests/Router/SocketRouterTest.php index 4efd6fd96..bbdbfccb5 100644 --- a/tests/Router/SocketRouterTest.php +++ b/tests/Router/SocketRouterTest.php @@ -90,11 +90,6 @@ class SocketRouterTest extends \PHPUnit\Framework\TestCase */ public function testDynamicRouteAdding() : void { - self::assertNotEquals( - [['dest' => '\Modules\Admin\Controller:viewSettingsGeneral']], - $this->router->route('backends_admin -settings=general -t 123') - ); - $this->router->add('^.*backends_admin -settings=general.*$', 'Controller:test'); self::assertEquals( [['dest' => 'Controller:test']], @@ -109,10 +104,6 @@ class SocketRouterTest extends \PHPUnit\Framework\TestCase */ public function testWithValidPermissions() : void { - if (!Autoloader::exists('\Modules\Admin\Controller')) { - self::markTestSkipped(); - } - self::assertTrue($this->router->importFromFile(__DIR__ . '/socketRouterTestFilePermission.php')); $perm = new class( @@ -146,10 +137,6 @@ class SocketRouterTest extends \PHPUnit\Framework\TestCase */ public function testWithInvalidPermissions() : void { - if (!Autoloader::exists('\Modules\Admin\Controller')) { - self::markTestSkipped(); - } - self::assertTrue($this->router->importFromFile(__DIR__ . '/socketRouterTestFilePermission.php')); $perm2 = new class( @@ -199,4 +186,69 @@ class SocketRouterTest extends \PHPUnit\Framework\TestCase ) ); } + + /** + * @testdox A data validation pattern validates matches correctly + * @covers phpOMS\Router\SocketRouter + * @group framework + */ + public function testDataValidation() : void + { + $this->router->add( + '^.*backends_admin -settings=general.*$', + 'Controller:test', + ['test_pattern' => '/^[a-z]*$/'] + ); + + self::assertEquals( + [['dest' => 'Controller:test']], + $this->router->route('backends_admin -settings=general -t 123', null, null, null, ['test_pattern' => 'abcdef']) + ); + } + + /** + * @testdox A data validation pattern invalidates missmatches + * @covers phpOMS\Router\SocketRouter + * @group framework + */ + public function testInvalidDataValidation() : void + { + $this->router->add( + '^.*backends_admin -settings=general.*$', + 'Controller:test', + ['test_pattern' => '/^[a-z]*$/'] + ); + + self::assertNotEquals( + [['dest' => 'Controller:test']], + $this->router->route('backends_admin -settings=general -t 123', null, null, null, ['test_pattern' => '123']) + ); + } + + /** + * @testdox A uri can be used for data population + * @covers phpOMS\Router\SocketRouter + * @group framework + */ + public function testDataFromPattern() : void + { + $this->router->add( + '^.*-settings=general.*$', + 'Controller:test', + [], + '/^.*?(settings)=([a-z]*).*?$/' + ); + + self::assertEquals( + [[ + 'dest' => 'Controller:test', + 'data' => [ + 'backends_admin -settings=general -t 123', + 'settings', + 'general', + ], + ]], + $this->router->route('backends_admin -settings=general -t 123') + ); + } } diff --git a/tests/Router/WebRouterTest.php b/tests/Router/WebRouterTest.php index 4cf52cabe..0a3965ba3 100644 --- a/tests/Router/WebRouterTest.php +++ b/tests/Router/WebRouterTest.php @@ -119,15 +119,6 @@ class WebRouterTest extends \PHPUnit\Framework\TestCase */ public function testDynamicRouteAdding() : void { - self::assertNotEquals( - [['dest' => '\Modules\Admin\Controller:viewSettingsGeneral']], - $this->router->route( - (new HttpRequest( - new HttpUri('http://test.com/backends/admin/settings/general/something?test') - ))->getUri()->getRoute() - ) - ); - $this->router->add('^.*/backends/admin/settings/general.*$', 'Controller:test', RouteVerb::GET | RouteVerb::SET); self::assertEquals( [['dest' => 'Controller:test']], diff --git a/tests/TestLoad.php b/tests/TestLoad.php new file mode 100644 index 000000000..cf5ab0e7b --- /dev/null +++ b/tests/TestLoad.php @@ -0,0 +1,27 @@ +