184e2cf4eSGreg Roach<?php 23cfcc809SGreg Roach 384e2cf4eSGreg Roach/** 484e2cf4eSGreg Roach * webtrees: online genealogy 589f7189bSGreg Roach * Copyright (C) 2021 webtrees development team 684e2cf4eSGreg Roach * This program is free software: you can redistribute it and/or modify 784e2cf4eSGreg Roach * it under the terms of the GNU General Public License as published by 884e2cf4eSGreg Roach * the Free Software Foundation, either version 3 of the License, or 984e2cf4eSGreg Roach * (at your option) any later version. 1084e2cf4eSGreg Roach * This program is distributed in the hope that it will be useful, 1184e2cf4eSGreg Roach * but WITHOUT ANY WARRANTY; without even the implied warranty of 1284e2cf4eSGreg Roach * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1384e2cf4eSGreg Roach * GNU General Public License for more details. 1484e2cf4eSGreg Roach * You should have received a copy of the GNU General Public License 1589f7189bSGreg Roach * along with this program. If not, see <https://www.gnu.org/licenses/>. 1684e2cf4eSGreg Roach */ 173cfcc809SGreg Roach 18e7f56f2aSGreg Roachdeclare(strict_types=1); 19e7f56f2aSGreg Roach 2084e2cf4eSGreg Roachnamespace Fisharebest\Webtrees; 2184e2cf4eSGreg Roach 22de2aa325SGreg Roachuse Aura\Router\Route; 23ee4364daSGreg Roachuse Aura\Router\RouterContainer; 24d403609dSGreg Roachuse Fig\Http\Message\RequestMethodInterface; 256fd01894SGreg Roachuse Fisharebest\Webtrees\Http\RequestHandlers\GedcomLoad; 262279b4f3SGreg Roachuse Fisharebest\Webtrees\Http\Routes\WebRoutes; 278136679eSGreg Roachuse Fisharebest\Webtrees\Module\ModuleThemeInterface; 288136679eSGreg Roachuse Fisharebest\Webtrees\Module\WebtreesTheme; 298c3e1068SGreg Roachuse Fisharebest\Webtrees\Services\MigrationService; 3071378461SGreg Roachuse Fisharebest\Webtrees\Services\ModuleService; 31126654d7SGreg Roachuse Fisharebest\Webtrees\Services\TimeoutService; 321e653452SGreg Roachuse Fisharebest\Webtrees\Services\TreeService; 330115bc16SGreg Roachuse Illuminate\Database\Capsule\Manager as DB; 3400c45d23SGreg Roachuse Nyholm\Psr7\Factory\Psr17Factory; 3500c45d23SGreg Roachuse Psr\Http\Message\ResponseFactoryInterface; 3600c45d23SGreg Roachuse Psr\Http\Message\ServerRequestFactoryInterface; 376ccdf4f0SGreg Roachuse Psr\Http\Message\ServerRequestInterface; 386ccdf4f0SGreg Roachuse Psr\Http\Message\StreamFactoryInterface; 396ccdf4f0SGreg Roachuse Psr\Http\Message\UploadedFileFactoryInterface; 406ccdf4f0SGreg Roachuse Psr\Http\Message\UploadedFileInterface; 4100c45d23SGreg Roachuse Psr\Http\Message\UriFactoryInterface; 4271378461SGreg Roach 436ccdf4f0SGreg Roachuse function app; 447def76c7SGreg Roachuse function basename; 456ccdf4f0SGreg Roachuse function filesize; 466ccdf4f0SGreg Roachuse function http_build_query; 4771378461SGreg Roach 486ccdf4f0SGreg Roachuse const UPLOAD_ERR_OK; 490115bc16SGreg Roach 5084e2cf4eSGreg Roach/** 5184e2cf4eSGreg Roach * Base class for unit tests 5284e2cf4eSGreg Roach */ 5371378461SGreg Roachclass TestCase extends \PHPUnit\Framework\TestCase 5484e2cf4eSGreg Roach{ 5574d6dc0eSGreg Roach /** @var object */ 5674d6dc0eSGreg Roach public static $mock_functions; 5757ab2231SGreg Roach /** @var bool */ 5857ab2231SGreg Roach protected static $uses_database = false; 5974d6dc0eSGreg Roach 60061b43d7SGreg Roach /** 61061b43d7SGreg Roach * Things to run once, before all the tests. 62061b43d7SGreg Roach */ 635e933c21SGreg Roach public static function setUpBeforeClass(): void 64061b43d7SGreg Roach { 65061b43d7SGreg Roach parent::setUpBeforeClass(); 66061b43d7SGreg Roach 67785274b8SGreg Roach $webtrees = new Webtrees(); 68785274b8SGreg Roach $webtrees->bootstrap(); 6900c45d23SGreg Roach 70785274b8SGreg Roach // PSR7 messages and PSR17 message-factories 71785274b8SGreg Roach Webtrees::set(ResponseFactoryInterface::class, Psr17Factory::class); 72785274b8SGreg Roach Webtrees::set(ServerRequestFactoryInterface::class, Psr17Factory::class); 73785274b8SGreg Roach Webtrees::set(StreamFactoryInterface::class, Psr17Factory::class); 74785274b8SGreg Roach Webtrees::set(UploadedFileFactoryInterface::class, Psr17Factory::class); 75785274b8SGreg Roach Webtrees::set(UriFactoryInterface::class, Psr17Factory::class); 766ccdf4f0SGreg Roach 77785274b8SGreg Roach // This is normally set in middleware. 78785274b8SGreg Roach Webtrees::set(ModuleThemeInterface::class, WebtreesTheme::class); 796ccdf4f0SGreg Roach 80ee4364daSGreg Roach // Need the routing table, to generate URLs. 812279b4f3SGreg Roach $router_container = new RouterContainer('/'); 822279b4f3SGreg Roach (new WebRoutes())->load($router_container->getMap()); 83785274b8SGreg Roach Webtrees::set(RouterContainer::class, $router_container); 84ee4364daSGreg Roach 85150f35adSGreg Roach I18N::init('en-US', true); 866ccdf4f0SGreg Roach 87061b43d7SGreg Roach if (static::$uses_database) { 88061b43d7SGreg Roach static::createTestDatabase(); 8971378461SGreg Roach 9071378461SGreg Roach // Boot modules 9171378461SGreg Roach (new ModuleService())->bootModules(new WebtreesTheme()); 92061b43d7SGreg Roach } 93061b43d7SGreg Roach } 94061b43d7SGreg Roach 95061b43d7SGreg Roach /** 9671378461SGreg Roach * Things to run once, AFTER all the tests. 9771378461SGreg Roach */ 985e933c21SGreg Roach public static function tearDownAfterClass(): void 9971378461SGreg Roach { 10071378461SGreg Roach if (static::$uses_database) { 10171378461SGreg Roach $pdo = DB::connection()->getPdo(); 10271378461SGreg Roach unset($pdo); 10371378461SGreg Roach } 10471378461SGreg Roach 10571378461SGreg Roach parent::tearDownAfterClass(); 10671378461SGreg Roach } 10771378461SGreg Roach 10871378461SGreg Roach /** 1096ccdf4f0SGreg Roach * Create an SQLite in-memory database for testing 1106ccdf4f0SGreg Roach */ 1116ccdf4f0SGreg Roach protected static function createTestDatabase(): void 1126ccdf4f0SGreg Roach { 1136ccdf4f0SGreg Roach $capsule = new DB(); 1146ccdf4f0SGreg Roach $capsule->addConnection([ 1156ccdf4f0SGreg Roach 'driver' => 'sqlite', 1166ccdf4f0SGreg Roach 'database' => ':memory:', 1176ccdf4f0SGreg Roach ]); 1186ccdf4f0SGreg Roach $capsule->setAsGlobal(); 119e16a1bfdSGreg Roach 1206ccdf4f0SGreg Roach // Migrations create logs, which requires an IP address, which requires a request 1216ccdf4f0SGreg Roach self::createRequest(); 1226ccdf4f0SGreg Roach 1236ccdf4f0SGreg Roach // Create tables 1243cfcc809SGreg Roach $migration_service = new MigrationService(); 1256ccdf4f0SGreg Roach $migration_service->updateSchema('\Fisharebest\Webtrees\Schema', 'WT_SCHEMA_VERSION', Webtrees::SCHEMA_VERSION); 1266ccdf4f0SGreg Roach 1276ccdf4f0SGreg Roach // Create config data 1286ccdf4f0SGreg Roach $migration_service->seedDatabase(); 1296ccdf4f0SGreg Roach } 1306ccdf4f0SGreg Roach 1316ccdf4f0SGreg Roach /** 13257ab2231SGreg Roach * Create a request and bind it into the container. 13357ab2231SGreg Roach * 13457ab2231SGreg Roach * @param string $method 13557ab2231SGreg Roach * @param string[] $query 13657ab2231SGreg Roach * @param string[] $params 13757ab2231SGreg Roach * @param UploadedFileInterface[] $files 138b3a775f6SGreg Roach * @param string[] $attributes 13957ab2231SGreg Roach * 14057ab2231SGreg Roach * @return ServerRequestInterface 14157ab2231SGreg Roach */ 1421a218474SGreg Roach protected static function createRequest( 1431a218474SGreg Roach string $method = RequestMethodInterface::METHOD_GET, 1441a218474SGreg Roach array $query = [], 1451a218474SGreg Roach array $params = [], 146b3a775f6SGreg Roach array $files = [], 147b3a775f6SGreg Roach array $attributes = [] 1481a218474SGreg Roach ): ServerRequestInterface { 14900c45d23SGreg Roach /** @var ServerRequestFactoryInterface */ 15000c45d23SGreg Roach $server_request_factory = app(ServerRequestFactoryInterface::class); 15100c45d23SGreg Roach 15257ab2231SGreg Roach $uri = 'https://webtrees.test/index.php?' . http_build_query($query); 15357ab2231SGreg Roach 15400c45d23SGreg Roach /** @var ServerRequestInterface $request */ 15500c45d23SGreg Roach $request = $server_request_factory 15657ab2231SGreg Roach ->createServerRequest($method, $uri) 15757ab2231SGreg Roach ->withQueryParams($query) 15857ab2231SGreg Roach ->withParsedBody($params) 15957ab2231SGreg Roach ->withUploadedFiles($files) 16057ab2231SGreg Roach ->withAttribute('base_url', 'https://webtrees.test') 16190a2f718SGreg Roach ->withAttribute('client-ip', '127.0.0.1') 162b5f5afdbSGreg Roach ->withAttribute('user', new GuestUser()) 163de2aa325SGreg Roach ->withAttribute('route', new Route()); 164b3a775f6SGreg Roach 165b3a775f6SGreg Roach foreach ($attributes as $key => $value) { 166b3a775f6SGreg Roach $request = $request->withAttribute($key, $value); 167b3a775f6SGreg Roach 168b3a775f6SGreg Roach if ($key === 'tree') { 169b3a775f6SGreg Roach app()->instance(Tree::class, $value); 170b3a775f6SGreg Roach } 171b3a775f6SGreg Roach } 17257ab2231SGreg Roach 17357ab2231SGreg Roach app()->instance(ServerRequestInterface::class, $request); 17457ab2231SGreg Roach 17557ab2231SGreg Roach return $request; 17657ab2231SGreg Roach } 17757ab2231SGreg Roach 17857ab2231SGreg Roach /** 179061b43d7SGreg Roach * Things to run before every test. 180061b43d7SGreg Roach */ 1815c48bcd6SGreg Roach protected function setUp(): void 1820115bc16SGreg Roach { 1830115bc16SGreg Roach parent::setUp(); 1840115bc16SGreg Roach 185061b43d7SGreg Roach if (static::$uses_database) { 186061b43d7SGreg Roach DB::connection()->beginTransaction(); 187061b43d7SGreg Roach } 188061b43d7SGreg Roach } 189061b43d7SGreg Roach 190061b43d7SGreg Roach /** 191061b43d7SGreg Roach * Things to run after every test 192061b43d7SGreg Roach */ 1935e933c21SGreg Roach protected function tearDown(): void 194a49feabaSGreg Roach { 19532f20c14SGreg Roach if (static::$uses_database) { 196061b43d7SGreg Roach DB::connection()->rollBack(); 197061b43d7SGreg Roach } 19832f20c14SGreg Roach 19932f20c14SGreg Roach Site::$preferences = []; 20032f20c14SGreg Roach 20132f20c14SGreg Roach Auth::logout(); 2020115bc16SGreg Roach } 2030115bc16SGreg Roach 2040115bc16SGreg Roach /** 2050115bc16SGreg Roach * Import a GEDCOM file into the test database. 2060115bc16SGreg Roach * 2070115bc16SGreg Roach * @param string $gedcom_file 208061b43d7SGreg Roach * 209061b43d7SGreg Roach * @return Tree 2100115bc16SGreg Roach */ 211061b43d7SGreg Roach protected function importTree(string $gedcom_file): Tree 2120115bc16SGreg Roach { 2131e653452SGreg Roach $tree_service = new TreeService(); 2141e653452SGreg Roach $tree = $tree_service->create(basename($gedcom_file), basename($gedcom_file)); 21500c45d23SGreg Roach $stream = app(StreamFactoryInterface::class)->createStreamFromFile(__DIR__ . '/data/' . $gedcom_file); 2161e653452SGreg Roach 2175cd281f4SGreg Roach $tree_service->importGedcomFile($tree, $stream, $gedcom_file); 2180115bc16SGreg Roach 219*c4943cffSGreg Roach $timeout_service = new TimeoutService(); 2205cd281f4SGreg Roach $controller = new GedcomLoad($timeout_service, $tree_service); 22157ab2231SGreg Roach $request = self::createRequest()->withAttribute('tree', $tree); 222126654d7SGreg Roach 223126654d7SGreg Roach do { 2246fd01894SGreg Roach $controller->handle($request); 225126654d7SGreg Roach 226126654d7SGreg Roach $imported = $tree->getPreference('imported'); 227126654d7SGreg Roach } while (!$imported); 228061b43d7SGreg Roach 229061b43d7SGreg Roach return $tree; 2300115bc16SGreg Roach } 2316ccdf4f0SGreg Roach 2326ccdf4f0SGreg Roach /** 2336ccdf4f0SGreg Roach * Create an uploaded file for a request. 2346ccdf4f0SGreg Roach * 2356ccdf4f0SGreg Roach * @param string $filename 2366ccdf4f0SGreg Roach * @param string $mime_type 2376ccdf4f0SGreg Roach * 2386ccdf4f0SGreg Roach * @return UploadedFileInterface 2396ccdf4f0SGreg Roach */ 2406ccdf4f0SGreg Roach protected function createUploadedFile(string $filename, string $mime_type): UploadedFileInterface 2416ccdf4f0SGreg Roach { 24200c45d23SGreg Roach /** @var StreamFactoryInterface */ 24300c45d23SGreg Roach $stream_factory = app(StreamFactoryInterface::class); 24400c45d23SGreg Roach 24500c45d23SGreg Roach /** @var UploadedFileFactoryInterface */ 24600c45d23SGreg Roach $uploaded_file_factory = app(UploadedFileFactoryInterface::class); 24700c45d23SGreg Roach 24800c45d23SGreg Roach $stream = $stream_factory->createStreamFromFile($filename); 2496ccdf4f0SGreg Roach $size = filesize($filename); 2506ccdf4f0SGreg Roach $status = UPLOAD_ERR_OK; 2516ccdf4f0SGreg Roach $client_name = basename($filename); 2526ccdf4f0SGreg Roach 25300c45d23SGreg Roach return $uploaded_file_factory->createUploadedFile($stream, $size, $status, $client_name, $mime_type); 2546ccdf4f0SGreg Roach } 25584e2cf4eSGreg Roach} 256