1e9e85398SGreg Roach<?php 23976b470SGreg Roach 3e9e85398SGreg Roach/** 4e9e85398SGreg Roach * webtrees: online genealogy 5d11be702SGreg Roach * Copyright (C) 2023 webtrees development team 6e9e85398SGreg Roach * This program is free software: you can redistribute it and/or modify 7e9e85398SGreg Roach * it under the terms of the GNU General Public License as published by 8e9e85398SGreg Roach * the Free Software Foundation, either version 3 of the License, or 9e9e85398SGreg Roach * (at your option) any later version. 10e9e85398SGreg Roach * This program is distributed in the hope that it will be useful, 11e9e85398SGreg Roach * but WITHOUT ANY WARRANTY; without even the implied warranty of 12e9e85398SGreg Roach * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13e9e85398SGreg Roach * GNU General Public License for more details. 14e9e85398SGreg 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/>. 16e9e85398SGreg Roach */ 17fcfa147eSGreg Roach 18e9e85398SGreg Roachdeclare(strict_types=1); 19e9e85398SGreg Roach 20e9e85398SGreg Roachnamespace Fisharebest\Webtrees; 21e9e85398SGreg Roach 2271378461SGreg Roachuse Fig\Http\Message\RequestMethodInterface; 2371378461SGreg Roachuse Fig\Http\Message\StatusCodeInterface; 247dcc0dd1SGreg Roachuse Fisharebest\Webtrees\Contracts\UserInterface; 2587cca37cSGreg Roachuse Fisharebest\Webtrees\Module\IndividualListModule; 267dcc0dd1SGreg Roachuse Fisharebest\Webtrees\Services\GedcomImportService; 277dcc0dd1SGreg Roachuse Fisharebest\Webtrees\Services\TreeService; 287dcc0dd1SGreg Roachuse Fisharebest\Webtrees\Services\UserService; 297dcc0dd1SGreg Roach 30*202c018bSGreg Roachuse PHPUnit\Framework\Attributes\CoversClass; 31*202c018bSGreg Roach 327dcc0dd1SGreg Roachuse function array_map; 337dcc0dd1SGreg Roachuse function preg_match_all; 34b9fc687eSGreg Roach 35*202c018bSGreg Roach#[CoversClass(IndividualListModule::class)] 36e5a6b4d4SGreg Roachclass IndividualListTest extends TestCase 37e9e85398SGreg Roach{ 38cd94ca66SGreg Roach protected static bool $uses_database = true; 39e9e85398SGreg Roach 407dcc0dd1SGreg Roach private Tree $tree; 417dcc0dd1SGreg Roach private User $user; 427dcc0dd1SGreg Roach 437dcc0dd1SGreg Roach public function setUp(): void 447dcc0dd1SGreg Roach { 45a26ec5edSGreg Roach parent::setUp(); 46a26ec5edSGreg Roach 477dcc0dd1SGreg Roach I18N::init('en-US'); 487dcc0dd1SGreg Roach 497dcc0dd1SGreg Roach $user_service = new UserService(); 507dcc0dd1SGreg Roach $tree_service = new TreeService(new GedcomImportService()); 517dcc0dd1SGreg Roach $this->tree = $tree_service->create('name', 'title'); 527dcc0dd1SGreg Roach $this->user = $user_service->create('user', 'User', 'user@example.com', 'secret'); 537dcc0dd1SGreg Roach $this->user->setPreference(UserInterface::PREF_IS_ADMINISTRATOR, '1'); 547dcc0dd1SGreg Roach $this->user->setPreference(UserInterface::PREF_AUTO_ACCEPT_EDITS, '1'); 557dcc0dd1SGreg Roach Auth::login($this->user); 567dcc0dd1SGreg Roach // The default "John Doe" individual will confuse the test results... 577dcc0dd1SGreg Roach Registry::individualFactory()->make('X1', $this->tree)->deleteRecord(); 587dcc0dd1SGreg Roach } 597dcc0dd1SGreg Roach 607dcc0dd1SGreg Roach public function testCollationOfInitials(): void 61e9e85398SGreg Roach { 62a26ec5edSGreg Roach $module = new IndividualListModule(); 63a26ec5edSGreg Roach 647dcc0dd1SGreg Roach $this->tree->createIndividual("0 @@ INDI\n1 NAME /Âaa/"); 657dcc0dd1SGreg Roach $this->tree->createIndividual("0 @@ INDI\n1 NAME /aaa/"); 667dcc0dd1SGreg Roach $this->tree->createIndividual("0 @@ INDI\n1 NAME /Ååå/"); 677dcc0dd1SGreg Roach $this->tree->createIndividual("0 @@ INDI\n1 NAME /æææ/"); 687dcc0dd1SGreg Roach $this->tree->createIndividual("0 @@ INDI\n1 NAME /Caa/"); 697dcc0dd1SGreg Roach $this->tree->createIndividual("0 @@ INDI\n1 NAME /Css/"); 707dcc0dd1SGreg Roach $this->tree->createIndividual("0 @@ INDI\n1 NAME /Dza/"); 71b9fc687eSGreg Roach 727dcc0dd1SGreg Roach I18N::init('en-US'); 737dcc0dd1SGreg Roach $request = self::createRequest(RequestMethodInterface::METHOD_GET, [], [], [], ['tree' => $this->tree]); 74a26ec5edSGreg Roach $response = $module->handle($request); 757dcc0dd1SGreg Roach $html = $response->getBody()->getContents(); 767dcc0dd1SGreg Roach preg_match_all('/%2Findividual-list&alpha=([^"&]+)/', $html, $matches); 777dcc0dd1SGreg Roach self::assertEquals(['A', 'C', 'D', 'Æ'], array_map(rawurldecode(...), $matches[1])); 78b9fc687eSGreg Roach 797dcc0dd1SGreg Roach I18N::init('sv'); 807dcc0dd1SGreg Roach $request = self::createRequest(RequestMethodInterface::METHOD_GET, [], [], [], ['tree' => $this->tree]); 81a26ec5edSGreg Roach $response = $module->handle($request); 827dcc0dd1SGreg Roach $html = $response->getBody()->getContents(); 837dcc0dd1SGreg Roach preg_match_all('/%2Findividual-list&alpha=([^"&]+)/', $html, $matches); 847dcc0dd1SGreg Roach self::assertEquals(['A', 'C', 'D', 'Å', 'Æ'], array_map(rawurldecode(...), $matches[1])); 85b9fc687eSGreg Roach 867dcc0dd1SGreg Roach I18N::init('hu'); 877dcc0dd1SGreg Roach $request = self::createRequest(RequestMethodInterface::METHOD_GET, [], [], [], ['tree' => $this->tree]); 88a26ec5edSGreg Roach $response = $module->handle($request); 897dcc0dd1SGreg Roach $html = $response->getBody()->getContents(); 907dcc0dd1SGreg Roach preg_match_all('/%2Findividual-list&alpha=([^"&]+)/', $html, $matches); 917dcc0dd1SGreg Roach self::assertEquals(['A', 'C', 'CS', 'DZ', 'Æ'], array_map(rawurldecode(...), $matches[1])); 927dcc0dd1SGreg Roach } 93a67cd39fSGreg Roach 94a26ec5edSGreg Roach public function xtestRedirectToCanonicalSurname(): void 957dcc0dd1SGreg Roach { 96a26ec5edSGreg Roach $module = new IndividualListModule(); 97a26ec5edSGreg Roach 987dcc0dd1SGreg Roach I18N::init('en-US'); 99a26ec5edSGreg Roach $request = self::createRequest(RequestMethodInterface::METHOD_GET, ['surname' => 'Muller'], [], [], ['tree' => $this->tree]); 100a26ec5edSGreg Roach $response = $module->handle($request); 101a26ec5edSGreg Roach self::assertSame(StatusCodeInterface::STATUS_MOVED_PERMANENTLY, $response->getStatusCode()); 102a26ec5edSGreg Roach self::assertStringContainsString('surname=MULLER', $response->getHeaderLine('Location')); 103a26ec5edSGreg Roach 1047dcc0dd1SGreg Roach $request = self::createRequest(RequestMethodInterface::METHOD_GET, ['surname' => 'MÜLLER'], [], [], ['tree' => $this->tree]); 105a26ec5edSGreg Roach $response = $module->handle($request); 1067dcc0dd1SGreg Roach self::assertSame(StatusCodeInterface::STATUS_MOVED_PERMANENTLY, $response->getStatusCode()); 1077dcc0dd1SGreg Roach self::assertStringContainsString('surname=MULLER', $response->getHeaderLine('Location')); 108b9fc687eSGreg Roach 1097dcc0dd1SGreg Roach I18N::init('de'); 1107dcc0dd1SGreg Roach $request = self::createRequest(RequestMethodInterface::METHOD_GET, ['surname' => 'MÜLLER'], [], [], ['tree' => $this->tree]); 111a26ec5edSGreg Roach $response = $module->handle($request); 1127dcc0dd1SGreg Roach self::assertSame(StatusCodeInterface::STATUS_MOVED_PERMANENTLY, $response->getStatusCode()); 1137dcc0dd1SGreg Roach self::assertStringContainsString('surname=MUELLER', $response->getHeaderLine('Location')); 1147dcc0dd1SGreg Roach } 1157dcc0dd1SGreg Roach 1167dcc0dd1SGreg Roach public function testCollationOfSurnames(): void 1177dcc0dd1SGreg Roach { 118a26ec5edSGreg Roach $module = new IndividualListModule(); 119a26ec5edSGreg Roach 1207dcc0dd1SGreg Roach $i1 = $this->tree->createIndividual("0 @@ INDI\n1 NAME /Muller/"); 1217dcc0dd1SGreg Roach $i2 = $this->tree->createIndividual("0 @@ INDI\n1 NAME /Müller/"); 1227dcc0dd1SGreg Roach $i3 = $this->tree->createIndividual("0 @@ INDI\n1 NAME /Mueller/"); 1237dcc0dd1SGreg Roach 1247dcc0dd1SGreg Roach I18N::init('en-US'); 1257dcc0dd1SGreg Roach $request = self::createRequest(RequestMethodInterface::METHOD_GET, ['surname' => 'MULLER'], [], [], ['tree' => $this->tree]); 126a26ec5edSGreg Roach $response = $module->handle($request); 1277dcc0dd1SGreg Roach $html = $response->getBody()->getContents(); 1287dcc0dd1SGreg Roach preg_match_all('/%2Fname%2Findividual%2F(X\d+)%2F/', $html, $matches); 1297dcc0dd1SGreg Roach self::assertEqualsCanonicalizing([$i1->xref(), $i2->xref()], $matches[1], 'English, so U should match U and Ü'); 1307dcc0dd1SGreg Roach 1317dcc0dd1SGreg Roach I18N::init('de'); 1327dcc0dd1SGreg Roach $request = self::createRequest(RequestMethodInterface::METHOD_GET, ['surname' => 'MULLER'], [], [], ['tree' => $this->tree]); 133a26ec5edSGreg Roach $response = $module->handle($request); 1347dcc0dd1SGreg Roach $html = $response->getBody()->getContents(); 1357dcc0dd1SGreg Roach preg_match_all('/%2Fname%2Findividual%2F(X\d+)%2F/', $html, $matches); 1367dcc0dd1SGreg Roach self::assertEqualsCanonicalizing([$i1->xref()], $matches[1], 'German, so U should only match U'); 1377dcc0dd1SGreg Roach 1387dcc0dd1SGreg Roach $request = self::createRequest(RequestMethodInterface::METHOD_GET, ['surname' => 'MUELLER'], [], [], ['tree' => $this->tree]); 139a26ec5edSGreg Roach $response = $module->handle($request); 1407dcc0dd1SGreg Roach $html = $response->getBody()->getContents(); 1417dcc0dd1SGreg Roach preg_match_all('/%2Fname%2Findividual%2F(X\d+)%2F/', $html, $matches); 1427dcc0dd1SGreg Roach self::assertEqualsCanonicalizing([$i2->xref(), $i3->xref()], $matches[1], 'German, so UE should also match Ü'); 1437dcc0dd1SGreg Roach } 1447dcc0dd1SGreg Roach 145a26ec5edSGreg Roach public function xtestUnknownVersusMissingSurname(): void 1467dcc0dd1SGreg Roach { 147a26ec5edSGreg Roach $module = new IndividualListModule(); 148a26ec5edSGreg Roach 1497dcc0dd1SGreg Roach $i1 = $this->tree->createIndividual("0 @@ INDI\n1 NAME John //"); 1507dcc0dd1SGreg Roach $i2 = $this->tree->createIndividual("0 @@ INDI\n1 NAME John"); 1517dcc0dd1SGreg Roach 1527dcc0dd1SGreg Roach $request = self::createRequest(RequestMethodInterface::METHOD_GET, ['alpha' => '@'], [], [], ['tree' => $this->tree]); 153a26ec5edSGreg Roach $response = $module->handle($request); 1547dcc0dd1SGreg Roach $html = $response->getBody()->getContents(); 1557dcc0dd1SGreg Roach preg_match_all('/%2Fname%2Findividual%2F(X\d+)%2F/', $html, $matches); 1567dcc0dd1SGreg Roach self::assertEqualsCanonicalizing([$i1->xref()], $matches[1]); 1577dcc0dd1SGreg Roach 1587dcc0dd1SGreg Roach $request = self::createRequest(RequestMethodInterface::METHOD_GET, ['alpha' => ','], [], [], ['tree' => $this->tree]); 159a26ec5edSGreg Roach $response = $module->handle($request); 1607dcc0dd1SGreg Roach $html = $response->getBody()->getContents(); 1617dcc0dd1SGreg Roach preg_match_all('/%2Fname%2Findividual%2F(X\d+)%2F/', $html, $matches); 1627dcc0dd1SGreg Roach self::assertEqualsCanonicalizing([$i2->xref()], $matches[1]); 1637dcc0dd1SGreg Roach } 1647dcc0dd1SGreg Roach 165a26ec5edSGreg Roach public function xtestAllSurnamesExcludesUnknownAndMissing(): void 1667dcc0dd1SGreg Roach { 167a26ec5edSGreg Roach $module = new IndividualListModule(); 168a26ec5edSGreg Roach 1697dcc0dd1SGreg Roach $i1 = $this->tree->createIndividual("0 @@ INDI\n1 NAME John /Black/"); 1707dcc0dd1SGreg Roach $i2 = $this->tree->createIndividual("0 @@ INDI\n1 NAME Mary /White/"); 1717dcc0dd1SGreg Roach $this->tree->createIndividual("0 @@ INDI\n1 NAME Peter //"); 1727dcc0dd1SGreg Roach $this->tree->createIndividual("0 @@ INDI\n1 NAME Paul"); 1737dcc0dd1SGreg Roach 1747dcc0dd1SGreg Roach $request = self::createRequest(RequestMethodInterface::METHOD_GET, ['show_all' => 'yes'], [], [], ['tree' => $this->tree]); 175a26ec5edSGreg Roach $response = $module->handle($request); 1767dcc0dd1SGreg Roach $html = $response->getBody()->getContents(); 1777dcc0dd1SGreg Roach preg_match_all('/individual-list&surname=([A-Z]+)/', $html, $matches); 1787dcc0dd1SGreg Roach self::assertEqualsCanonicalizing(['BLACK', 'WHITE'], $matches[1]); 1797dcc0dd1SGreg Roach 1807dcc0dd1SGreg Roach $request = self::createRequest(RequestMethodInterface::METHOD_GET, ['show_all' => 'yes', 'show' => 'indi'], [], [], ['tree' => $this->tree]); 181a26ec5edSGreg Roach $response = $module->handle($request); 1827dcc0dd1SGreg Roach $html = $response->getBody()->getContents(); 1837dcc0dd1SGreg Roach preg_match_all('/%2Fname%2Findividual%2F(X\d+)%2F/', $html, $matches); 1847dcc0dd1SGreg Roach self::assertEqualsCanonicalizing([$i1->xref(), $i2->xref()], $matches[1]); 1857dcc0dd1SGreg Roach } 1867dcc0dd1SGreg Roach 187a26ec5edSGreg Roach public function xtestSurnameInitial(): void 1887dcc0dd1SGreg Roach { 189a26ec5edSGreg Roach $module = new IndividualListModule(); 190a26ec5edSGreg Roach 1917dcc0dd1SGreg Roach $i1 = $this->tree->createIndividual("0 @@ INDI\n1 NAME John /Black/"); 1927dcc0dd1SGreg Roach $i2 = $this->tree->createIndividual("0 @@ INDI\n1 NAME Mary /Brown/"); 1937dcc0dd1SGreg Roach $this->tree->createIndividual("0 @@ INDI\n1 NAME Peter /White/"); 1947dcc0dd1SGreg Roach $this->tree->createIndividual("0 @@ INDI\n1 NAME Paul /Green/"); 1957dcc0dd1SGreg Roach 1967dcc0dd1SGreg Roach $request = self::createRequest(RequestMethodInterface::METHOD_GET, ['alpha' => 'B'], [], [], ['tree' => $this->tree]); 197a26ec5edSGreg Roach $response = $module->handle($request); 1987dcc0dd1SGreg Roach $html = $response->getBody()->getContents(); 1997dcc0dd1SGreg Roach preg_match_all('/individual-list&surname=([A-Z]+)/', $html, $matches); 2007dcc0dd1SGreg Roach self::assertEqualsCanonicalizing(['BLACK', 'BROWN'], $matches[1]); 2017dcc0dd1SGreg Roach 2027dcc0dd1SGreg Roach $request = self::createRequest(RequestMethodInterface::METHOD_GET, ['alpha' => 'B', 'show' => 'indi'], [], [], ['tree' => $this->tree]); 203a26ec5edSGreg Roach $response = $module->handle($request); 2047dcc0dd1SGreg Roach $html = $response->getBody()->getContents(); 2057dcc0dd1SGreg Roach preg_match_all('/%2Fname%2Findividual%2F(X\d+)%2F/', $html, $matches); 2067dcc0dd1SGreg Roach self::assertEqualsCanonicalizing([$i1->xref(), $i2->xref()], $matches[1]); 207e9e85398SGreg Roach } 208e9e85398SGreg Roach} 209