1a25f0a04SGreg Roach<?php 23976b470SGreg Roach 3a25f0a04SGreg Roach/** 4a25f0a04SGreg Roach * webtrees: online genealogy 5d11be702SGreg Roach * Copyright (C) 2023 webtrees development team 6a25f0a04SGreg Roach * This program is free software: you can redistribute it and/or modify 7a25f0a04SGreg Roach * it under the terms of the GNU General Public License as published by 8a25f0a04SGreg Roach * the Free Software Foundation, either version 3 of the License, or 9a25f0a04SGreg Roach * (at your option) any later version. 10a25f0a04SGreg Roach * This program is distributed in the hope that it will be useful, 11a25f0a04SGreg Roach * but WITHOUT ANY WARRANTY; without even the implied warranty of 12a25f0a04SGreg Roach * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13a25f0a04SGreg Roach * GNU General Public License for more details. 14a25f0a04SGreg 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/>. 16a25f0a04SGreg Roach */ 17fcfa147eSGreg Roach 18e7f56f2aSGreg Roachdeclare(strict_types=1); 19e7f56f2aSGreg Roach 2084e2cf4eSGreg Roachnamespace Fisharebest\Webtrees; 21a25f0a04SGreg Roach 2269675509SGreg Roachuse Fisharebest\Webtrees\Contracts\CacheFactoryInterface; 231fe542e9SGreg Roachuse Fisharebest\Webtrees\Contracts\UserInterface; 2469c05a6eSGreg Roachuse Fisharebest\Webtrees\Services\GedcomExportService; 252c685d76SGreg Roachuse Fisharebest\Webtrees\Services\GedcomImportService; 265afbc57aSGreg Roachuse Fisharebest\Webtrees\Services\TreeService; 27e5a6b4d4SGreg Roachuse Fisharebest\Webtrees\Services\UserService; 283cfcc809SGreg Roachuse InvalidArgumentException; 2916ecfcafSGreg Roachuse Nyholm\Psr7\Factory\Psr17Factory; 30*202c018bSGreg Roachuse PHPUnit\Framework\Attributes\CoversClass; 3169675509SGreg Roachuse Symfony\Component\Cache\Adapter\NullAdapter; 323976b470SGreg Roach 33ea517a3bSGreg Roachuse function fclose; 34ea517a3bSGreg Roachuse function file_get_contents; 35ea517a3bSGreg Roachuse function preg_replace; 3694026f20SGreg Roachuse function stream_get_contents; 3794026f20SGreg Roach 38*202c018bSGreg Roach#[CoversClass(Tree::class)] 39*202c018bSGreg Roach#[CoversClass(TreeService::class)] 40*202c018bSGreg Roach#[CoversClass(GedcomExportService::class)] 41e5a6b4d4SGreg Roachclass TreeTest extends TestCase 42c1010edaSGreg Roach{ 43cd94ca66SGreg Roach protected static bool $uses_database = true; 44126654d7SGreg Roach 4592a78a2fSGreg Roach /** 4692a78a2fSGreg Roach * Things to run before every test. 4792a78a2fSGreg Roach */ 4857b69958SGreg Roach protected function setUp(): void 4969675509SGreg Roach { 5069675509SGreg Roach parent::setUp(); 5169675509SGreg Roach 52cd94ca66SGreg Roach $cache_factory = $this->createMock(CacheFactoryInterface::class); 5369675509SGreg Roach $cache_factory->method('array')->willReturn(new Cache(new NullAdapter())); 546b9cb339SGreg Roach Registry::cache($cache_factory); 5569675509SGreg Roach } 5669675509SGreg Roach 57126654d7SGreg Roach public function testConstructor(): void 58c1010edaSGreg Roach { 592c685d76SGreg Roach $gedcom_import_service = new GedcomImportService(); 602c685d76SGreg Roach $tree_service = new TreeService($gedcom_import_service); 611e653452SGreg Roach $tree = $tree_service->create('name', 'title'); 62126654d7SGreg Roach 635e933c21SGreg Roach self::assertSame('name', $tree->name()); 645e933c21SGreg Roach self::assertSame('title', $tree->title()); 65126654d7SGreg Roach } 66126654d7SGreg Roach 67af343084SGreg Roach public function testTreePreferences(): void 68126654d7SGreg Roach { 692c685d76SGreg Roach $gedcom_import_service = new GedcomImportService(); 702c685d76SGreg Roach $tree_service = new TreeService($gedcom_import_service); 711e653452SGreg Roach $tree = $tree_service->create('name', 'title'); 72126654d7SGreg Roach 73126654d7SGreg Roach $tree->setPreference('foo', 'bar'); 748a07c98eSGreg Roach $pref = $tree->getPreference('foo'); 755e933c21SGreg Roach self::assertSame('bar', $pref); 76a25f0a04SGreg Roach } 77af343084SGreg Roach 78af343084SGreg Roach public function testUserTreePreferences(): void 79af343084SGreg Roach { 80e5a6b4d4SGreg Roach $user_service = new UserService(); 812c685d76SGreg Roach $gedcom_import_service = new GedcomImportService(); 822c685d76SGreg Roach $tree_service = new TreeService($gedcom_import_service); 831e653452SGreg Roach $tree = $tree_service->create('name', 'title'); 84e5a6b4d4SGreg Roach $user = $user_service->create('user', 'User', 'user@example.com', 'secret'); 85af343084SGreg Roach 86af343084SGreg Roach $pref = $tree->getUserPreference($user, 'foo', 'default'); 875e933c21SGreg Roach self::assertSame('default', $pref); 88af343084SGreg Roach 89af343084SGreg Roach $tree->setUserPreference($user, 'foo', 'bar'); 90af343084SGreg Roach $pref = $tree->getUserPreference($user, 'foo', 'default'); 915e933c21SGreg Roach self::assertSame('bar', $pref); 927d76853dSGreg Roach } 937d76853dSGreg Roach 947d76853dSGreg Roach public function testCreateInvalidIndividual(): void 957d76853dSGreg Roach { 963cfcc809SGreg Roach $this->expectException(InvalidArgumentException::class); 973cfcc809SGreg Roach 98e5a6b4d4SGreg Roach $user_service = new UserService(); 992c685d76SGreg Roach $gedcom_import_service = new GedcomImportService(); 1002c685d76SGreg Roach $tree_service = new TreeService($gedcom_import_service); 1011e653452SGreg Roach $tree = $tree_service->create('name', 'title'); 102e5a6b4d4SGreg Roach $user = $user_service->create('user', 'User', 'user@example.com', 'secret'); 1031fe542e9SGreg Roach $user->setPreference(UserInterface::PREF_IS_ADMINISTRATOR, '1'); 1047d76853dSGreg Roach Auth::login($user); 1057d76853dSGreg Roach 1067d76853dSGreg Roach $tree->createIndividual("0 @@ FOO\n1 SEX U"); 1077d76853dSGreg Roach } 1087d76853dSGreg Roach 109963fbaeeSGreg Roach public function testCreateIndividual(): void 110963fbaeeSGreg Roach { 111e5a6b4d4SGreg Roach $user_service = new UserService(); 1122c685d76SGreg Roach $gedcom_import_service = new GedcomImportService(); 1132c685d76SGreg Roach $tree_service = new TreeService($gedcom_import_service); 1141e653452SGreg Roach $tree = $tree_service->create('name', 'title'); 115e5a6b4d4SGreg Roach $user = $user_service->create('user', 'User', 'user@example.com', 'secret'); 1161fe542e9SGreg Roach $user->setPreference(UserInterface::PREF_IS_ADMINISTRATOR, '1'); 117963fbaeeSGreg Roach Auth::login($user); 118963fbaeeSGreg Roach 1198f9b0fb2SGreg Roach $record = $tree->createIndividual("0 @@ INDI\n1 SEX F\n1 NAME Foo /Bar/"); 1205e933c21SGreg Roach self::assertTrue($record->isPendingAddition()); 121963fbaeeSGreg Roach 1221fe542e9SGreg Roach $user->setPreference(UserInterface::PREF_AUTO_ACCEPT_EDITS, '1'); 1238f9b0fb2SGreg Roach $record = $tree->createIndividual("0 @@ INDI\n1 SEX F\n1 NAME Foo /Bar/"); 1245e933c21SGreg Roach self::assertFalse($record->isPendingAddition()); 1258f9b0fb2SGreg Roach } 126963fbaeeSGreg Roach 1277d76853dSGreg Roach public function testCreateInvalidFamily(): void 1288f9b0fb2SGreg Roach { 1293cfcc809SGreg Roach $this->expectException(InvalidArgumentException::class); 1303cfcc809SGreg Roach 131e5a6b4d4SGreg Roach $user_service = new UserService(); 1322c685d76SGreg Roach $gedcom_import_service = new GedcomImportService(); 1332c685d76SGreg Roach $tree_service = new TreeService($gedcom_import_service); 1341e653452SGreg Roach $tree = $tree_service->create('name', 'title'); 135e5a6b4d4SGreg Roach $user = $user_service->create('user', 'User', 'user@example.com', 'secret'); 1361fe542e9SGreg Roach $user->setPreference(UserInterface::PREF_IS_ADMINISTRATOR, '1'); 1377d76853dSGreg Roach Auth::login($user); 138963fbaeeSGreg Roach 1397d76853dSGreg Roach $tree->createFamily("0 @@ FOO\n1 MARR Y"); 1408f9b0fb2SGreg Roach } 141963fbaeeSGreg Roach 1428f9b0fb2SGreg Roach public function testCreateFamily(): void 1438f9b0fb2SGreg Roach { 144e5a6b4d4SGreg Roach $user_service = new UserService(); 1452c685d76SGreg Roach $gedcom_import_service = new GedcomImportService(); 1462c685d76SGreg Roach $tree_service = new TreeService($gedcom_import_service); 1471e653452SGreg Roach $tree = $tree_service->create('name', 'title'); 148e5a6b4d4SGreg Roach $user = $user_service->create('user', 'User', 'user@example.com', 'secret'); 1491fe542e9SGreg Roach $user->setPreference(UserInterface::PREF_IS_ADMINISTRATOR, '1'); 1508f9b0fb2SGreg Roach Auth::login($user); 1518f9b0fb2SGreg Roach 1528f9b0fb2SGreg Roach $record = $tree->createFamily("0 @@ FAM\n1 MARR Y"); 1535e933c21SGreg Roach self::assertTrue($record->isPendingAddition()); 1548f9b0fb2SGreg Roach 1551fe542e9SGreg Roach $user->setPreference(UserInterface::PREF_AUTO_ACCEPT_EDITS, '1'); 1568f9b0fb2SGreg Roach $record = $tree->createFamily("0 @@ FAM\n1 MARR Y"); 1575e933c21SGreg Roach self::assertFalse($record->isPendingAddition()); 1588f9b0fb2SGreg Roach } 1598f9b0fb2SGreg Roach 1607d76853dSGreg Roach public function testCreateInvalidMediaObject(): void 1617d76853dSGreg Roach { 1623cfcc809SGreg Roach $this->expectException(InvalidArgumentException::class); 1633cfcc809SGreg Roach 164e5a6b4d4SGreg Roach $user_service = new UserService(); 1652c685d76SGreg Roach $gedcom_import_service = new GedcomImportService(); 1662c685d76SGreg Roach $tree_service = new TreeService($gedcom_import_service); 1671e653452SGreg Roach $tree = $tree_service->create('name', 'title'); 168e5a6b4d4SGreg Roach $user = $user_service->create('user', 'User', 'user@example.com', 'secret'); 1691fe542e9SGreg Roach $user->setPreference(UserInterface::PREF_IS_ADMINISTRATOR, '1'); 1707d76853dSGreg Roach Auth::login($user); 1717d76853dSGreg Roach 1727d76853dSGreg Roach $tree->createMediaObject("0 @@ FOO\n1 MARR Y"); 1737d76853dSGreg Roach } 1747d76853dSGreg Roach 1757d76853dSGreg Roach public function testCreateMediaObject(): void 1767d76853dSGreg Roach { 177e5a6b4d4SGreg Roach $user_service = new UserService(); 1782c685d76SGreg Roach $gedcom_import_service = new GedcomImportService(); 1792c685d76SGreg Roach $tree_service = new TreeService($gedcom_import_service); 1801e653452SGreg Roach $tree = $tree_service->create('name', 'title'); 181e5a6b4d4SGreg Roach $user = $user_service->create('user', 'User', 'user@example.com', 'secret'); 1821fe542e9SGreg Roach $user->setPreference(UserInterface::PREF_IS_ADMINISTRATOR, '1'); 1837d76853dSGreg Roach Auth::login($user); 1847d76853dSGreg Roach 1857d76853dSGreg Roach $record = $tree->createMediaObject("0 @@ OBJE\n1 FILE foo.jpeg"); 1865e933c21SGreg Roach self::assertTrue($record->isPendingAddition()); 1877d76853dSGreg Roach 1881fe542e9SGreg Roach $user->setPreference(UserInterface::PREF_AUTO_ACCEPT_EDITS, '1'); 1897d76853dSGreg Roach $record = $tree->createMediaObject("0 @@ OBJE\n1 FILE foo.jpeg"); 1905e933c21SGreg Roach self::assertFalse($record->isPendingAddition()); 1917d76853dSGreg Roach } 1927d76853dSGreg Roach 193bec87e94SGreg Roach public function testCreateInvalidRecord(): void 194bec87e94SGreg Roach { 1953cfcc809SGreg Roach $this->expectException(InvalidArgumentException::class); 1963cfcc809SGreg Roach 197e5a6b4d4SGreg Roach $user_service = new UserService(); 1982c685d76SGreg Roach $gedcom_import_service = new GedcomImportService(); 1992c685d76SGreg Roach $tree_service = new TreeService($gedcom_import_service); 2001e653452SGreg Roach $tree = $tree_service->create('name', 'title'); 201e5a6b4d4SGreg Roach $user = $user_service->create('user', 'User', 'user@example.com', 'secret'); 2021fe542e9SGreg Roach $user->setPreference(UserInterface::PREF_IS_ADMINISTRATOR, '1'); 203bec87e94SGreg Roach Auth::login($user); 204bec87e94SGreg Roach 205bec87e94SGreg Roach $tree->createRecord("0 @@FOO\n1 NOTE noted"); 206bec87e94SGreg Roach } 207bec87e94SGreg Roach 208bec87e94SGreg Roach public function testCreateRecord(): void 209bec87e94SGreg Roach { 210e5a6b4d4SGreg Roach $user_service = new UserService(); 2112c685d76SGreg Roach $gedcom_import_service = new GedcomImportService(); 2122c685d76SGreg Roach $tree_service = new TreeService($gedcom_import_service); 2131e653452SGreg Roach $tree = $tree_service->create('name', 'title'); 214e5a6b4d4SGreg Roach $user = $user_service->create('user', 'User', 'user@example.com', 'secret'); 2151fe542e9SGreg Roach $user->setPreference(UserInterface::PREF_IS_ADMINISTRATOR, '1'); 216bec87e94SGreg Roach Auth::login($user); 217bec87e94SGreg Roach 218bec87e94SGreg Roach $record = $tree->createRecord("0 @@ FOO\n1 NOTE noted"); 2195e933c21SGreg Roach self::assertTrue($record->isPendingAddition()); 220bec87e94SGreg Roach 2211fe542e9SGreg Roach $user->setPreference(UserInterface::PREF_AUTO_ACCEPT_EDITS, '1'); 222bec87e94SGreg Roach $record = $tree->createRecord("0 @@ FOO\n1 NOTE noted"); 2235e933c21SGreg Roach self::assertFalse($record->isPendingAddition()); 224bec87e94SGreg Roach } 225bec87e94SGreg Roach 2268f9b0fb2SGreg Roach public function testSignificantIndividual(): void 2278f9b0fb2SGreg Roach { 2282c685d76SGreg Roach $gedcom_import_service = new GedcomImportService(); 229e5a6b4d4SGreg Roach $user_service = new UserService(); 2302c685d76SGreg Roach $tree_service = new TreeService($gedcom_import_service); 2311e653452SGreg Roach $tree = $tree_service->create('name', 'title'); 232e5a6b4d4SGreg Roach $user = $user_service->create('user', 'User', 'user@example.com', 'secret'); 2331fe542e9SGreg Roach $user->setPreference(UserInterface::PREF_AUTO_ACCEPT_EDITS, '1'); 2348f9b0fb2SGreg Roach Auth::login($user); 2358f9b0fb2SGreg Roach 2365afbc57aSGreg Roach // Delete the tree's default individual. 2372c685d76SGreg Roach $gedcom_import_service->updateRecord('0 @X1@ INDI', $tree, true); 2385afbc57aSGreg Roach 2391f244d77SGreg Roach // No individuals in tree? Fake individual 2405e933c21SGreg Roach self::assertSame('I', $tree->significantIndividual($user)->xref()); 2418f9b0fb2SGreg Roach 2428f9b0fb2SGreg Roach $record1 = $tree->createIndividual("0 @@ INDI\n1 SEX F\n1 NAME Foo /Bar/"); 2438f9b0fb2SGreg Roach $record2 = $tree->createIndividual("0 @@ INDI\n1 SEX F\n1 NAME Foo /Bar/"); 2448f9b0fb2SGreg Roach $record3 = $tree->createIndividual("0 @@ INDI\n1 SEX F\n1 NAME Foo /Bar/"); 2458f9b0fb2SGreg Roach $record4 = $tree->createIndividual("0 @@ INDI\n1 SEX F\n1 NAME Foo /Bar/"); 2468f9b0fb2SGreg Roach 2478f9b0fb2SGreg Roach // Individuals exist? First one (lowest XREF). 2485e933c21SGreg Roach self::assertSame($record1->xref(), $tree->significantIndividual($user)->xref()); 2498f9b0fb2SGreg Roach 2508f9b0fb2SGreg Roach // Preference for tree? 2518f9b0fb2SGreg Roach $tree->setPreference('PEDIGREE_ROOT_ID', $record2->xref()); 2525e933c21SGreg Roach self::assertSame($record2->xref(), $tree->significantIndividual($user)->xref()); 2538f9b0fb2SGreg Roach 2548f9b0fb2SGreg Roach // User preference 2551fe542e9SGreg Roach $tree->setUserPreference($user, UserInterface::PREF_TREE_ACCOUNT_XREF, $record3->xref()); 2565e933c21SGreg Roach self::assertSame($record3->xref(), $tree->significantIndividual($user)->xref()); 2578f9b0fb2SGreg Roach 2588f9b0fb2SGreg Roach // User record 2591fe542e9SGreg Roach $tree->setUserPreference($user, UserInterface::PREF_TREE_DEFAULT_XREF, $record4->xref()); 2605e933c21SGreg Roach self::assertSame($record4->xref(), $tree->significantIndividual($user)->xref()); 261963fbaeeSGreg Roach } 262a7890280SGreg Roach 263a7890280SGreg Roach public function testImportAndDeleteGedcomFile(): void 264a7890280SGreg Roach { 2652c685d76SGreg Roach $gedcom_import_service = new GedcomImportService(); 2662c685d76SGreg Roach $tree_service = new TreeService($gedcom_import_service); 267a7890280SGreg Roach $tree = $this->importTree('demo.ged'); 2685e933c21SGreg Roach self::assertNotNull($tree_service->all()->get('demo.ged')); 269432ff88aSGreg Roach Site::setPreference('DEFAULT_GEDCOM', $tree->name()); 270a7890280SGreg Roach 2715afbc57aSGreg Roach $tree_service->delete($tree); 272432ff88aSGreg Roach 2735e933c21SGreg Roach self::assertNull($tree_service->all()->get('demo.ged')); 2745e933c21SGreg Roach self::assertSame('', Site::getPreference('DEFAULT_GEDCOM')); 275a7890280SGreg Roach } 27615a3f100SGreg Roach 27715a3f100SGreg Roach public function testHasPendingEdits(): void 27815a3f100SGreg Roach { 279e5a6b4d4SGreg Roach $user_service = new UserService(); 28015a3f100SGreg Roach $tree = $this->importTree('demo.ged'); 281e5a6b4d4SGreg Roach $user = $user_service->create('admin', 'Administrator', 'admin@example.com', 'secret'); 2821fe542e9SGreg Roach $user->setPreference(UserInterface::PREF_IS_ADMINISTRATOR, '1'); 28315a3f100SGreg Roach Auth::login($user); 28415a3f100SGreg Roach 2851fe542e9SGreg Roach $user->setPreference(UserInterface::PREF_AUTO_ACCEPT_EDITS, '1'); 28615a3f100SGreg Roach $tree->createIndividual("0 @@ INDI\n1 SEX F\n1 NAME Foo /Bar/"); 2875e933c21SGreg Roach self::assertFalse($tree->hasPendingEdit()); 28815a3f100SGreg Roach 2891fe542e9SGreg Roach $user->setPreference(UserInterface::PREF_AUTO_ACCEPT_EDITS, ''); 29015a3f100SGreg Roach $tree->createIndividual("0 @@ INDI\n1 SEX F\n1 NAME Foo /Bar/"); 2915e933c21SGreg Roach self::assertTrue($tree->hasPendingEdit()); 29215a3f100SGreg Roach } 29394026f20SGreg Roach 29494026f20SGreg Roach public function testExportGedcom(): void 29594026f20SGreg Roach { 29694026f20SGreg Roach $tree = $this->importTree('demo.ged'); 29794026f20SGreg Roach 29816ecfcafSGreg Roach $gedcom_export_service = new GedcomExportService(new Psr17Factory(), new Psr17Factory()); 29994026f20SGreg Roach 300ea517a3bSGreg Roach $resource = $gedcom_export_service->export($tree, true); 30194026f20SGreg Roach $original = file_get_contents(__DIR__ . '/../data/demo.ged'); 302ea517a3bSGreg Roach $export = stream_get_contents($resource); 303ea517a3bSGreg Roach fclose($resource); 30494026f20SGreg Roach 30569c05a6eSGreg Roach // The version, date and time in the HEAD record will be different. 30669c05a6eSGreg Roach $original = preg_replace('/\n2 VERS .*/', '', $original, 1); 30769c05a6eSGreg Roach $export = preg_replace('/\n2 VERS .*/', '', $export, 1); 30894026f20SGreg Roach $original = preg_replace('/\n1 DATE .. ... ..../', '', $original, 1); 30994026f20SGreg Roach $export = preg_replace('/\n1 DATE .. ... ..../', '', $export, 1); 31094026f20SGreg Roach $original = preg_replace('/\n2 TIME ..:..:../', '', $original, 1); 31194026f20SGreg Roach $export = preg_replace('/\n2 TIME ..:..:../', '', $export, 1); 31294026f20SGreg Roach 3135e933c21SGreg Roach self::assertSame($original, $export); 31494026f20SGreg Roach } 315a25f0a04SGreg Roach} 316