xref: /webtrees/tests/feature/IndividualListTest.php (revision 7dcc0dd1f98a779ae8ed3c9c0b53d14ead31a778)
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;
24*7dcc0dd1SGreg Roachuse Fisharebest\Webtrees\Contracts\UserInterface;
2587cca37cSGreg Roachuse Fisharebest\Webtrees\Module\IndividualListModule;
26*7dcc0dd1SGreg Roachuse Fisharebest\Webtrees\Services\GedcomImportService;
27*7dcc0dd1SGreg Roachuse Fisharebest\Webtrees\Services\TreeService;
28*7dcc0dd1SGreg Roachuse Fisharebest\Webtrees\Services\UserService;
29*7dcc0dd1SGreg Roach
30*7dcc0dd1SGreg Roachuse function array_map;
31*7dcc0dd1SGreg Roachuse function preg_match_all;
32b9fc687eSGreg Roach
33e9e85398SGreg Roach/**
34b9fc687eSGreg Roach * Test the individual lists.
35e9e85398SGreg Roach *
36e9e85398SGreg Roach * @coversNothing
37e9e85398SGreg Roach */
38e5a6b4d4SGreg Roachclass IndividualListTest extends TestCase
39e9e85398SGreg Roach{
40cd94ca66SGreg Roach    protected static bool $uses_database = true;
41e9e85398SGreg Roach
42*7dcc0dd1SGreg Roach    private IndividualListModule $module;
43*7dcc0dd1SGreg Roach    private Tree                 $tree;
44*7dcc0dd1SGreg Roach    private User                 $user;
45*7dcc0dd1SGreg Roach
46*7dcc0dd1SGreg Roach    public function setUp(): void
47*7dcc0dd1SGreg Roach    {
48*7dcc0dd1SGreg Roach        I18N::init('en-US');
49*7dcc0dd1SGreg Roach
50*7dcc0dd1SGreg Roach        $this->module = new IndividualListModule();
51*7dcc0dd1SGreg Roach        $user_service = new UserService();
52*7dcc0dd1SGreg Roach        $tree_service = new TreeService(new GedcomImportService());
53*7dcc0dd1SGreg Roach        $this->tree   = $tree_service->create('name', 'title');
54*7dcc0dd1SGreg Roach        $this->user   = $user_service->create('user', 'User', 'user@example.com', 'secret');
55*7dcc0dd1SGreg Roach        $this->user->setPreference(UserInterface::PREF_IS_ADMINISTRATOR, '1');
56*7dcc0dd1SGreg Roach        $this->user->setPreference(UserInterface::PREF_AUTO_ACCEPT_EDITS, '1');
57*7dcc0dd1SGreg Roach        Auth::login($this->user);
58*7dcc0dd1SGreg Roach        // The default "John Doe" individual will confuse the test results...
59*7dcc0dd1SGreg Roach        Registry::individualFactory()->make('X1', $this->tree)->deleteRecord();
60*7dcc0dd1SGreg Roach    }
61*7dcc0dd1SGreg Roach
62*7dcc0dd1SGreg Roach    public function tearDown(): void
63*7dcc0dd1SGreg Roach    {
64*7dcc0dd1SGreg Roach        $tree_service = new TreeService(new GedcomImportService());
65*7dcc0dd1SGreg Roach        $tree_service->delete($this->tree);
66*7dcc0dd1SGreg Roach
67*7dcc0dd1SGreg Roach        $user_service = new UserService();
68*7dcc0dd1SGreg Roach        $user_service->delete($this->user);
69*7dcc0dd1SGreg Roach    }
70*7dcc0dd1SGreg Roach
71e9e85398SGreg Roach    /**
725e933c21SGreg Roach     * @covers \Fisharebest\Webtrees\Module\IndividualListModule
73e9e85398SGreg Roach     */
74*7dcc0dd1SGreg Roach    public function testCollationOfInitials(): void
75e9e85398SGreg Roach    {
76*7dcc0dd1SGreg Roach        $this->tree->createIndividual("0 @@ INDI\n1 NAME /Âaa/");
77*7dcc0dd1SGreg Roach        $this->tree->createIndividual("0 @@ INDI\n1 NAME /aaa/");
78*7dcc0dd1SGreg Roach        $this->tree->createIndividual("0 @@ INDI\n1 NAME /Ååå/");
79*7dcc0dd1SGreg Roach        $this->tree->createIndividual("0 @@ INDI\n1 NAME /æææ/");
80*7dcc0dd1SGreg Roach        $this->tree->createIndividual("0 @@ INDI\n1 NAME /Caa/");
81*7dcc0dd1SGreg Roach        $this->tree->createIndividual("0 @@ INDI\n1 NAME /Css/");
82*7dcc0dd1SGreg Roach        $this->tree->createIndividual("0 @@ INDI\n1 NAME /Dza/");
83b9fc687eSGreg Roach
84*7dcc0dd1SGreg Roach        I18N::init('en-US');
85*7dcc0dd1SGreg Roach        $request  = self::createRequest(RequestMethodInterface::METHOD_GET, [], [], [], ['tree' => $this->tree]);
86*7dcc0dd1SGreg Roach        $response = $this->module->handle($request);
87*7dcc0dd1SGreg Roach        $html     = $response->getBody()->getContents();
88*7dcc0dd1SGreg Roach        preg_match_all('/%2Findividual-list&amp;alpha=([^"&]+)/', $html, $matches);
89*7dcc0dd1SGreg Roach        self::assertEquals(['A', 'C', 'D', 'Æ'], array_map(rawurldecode(...), $matches[1]));
90b9fc687eSGreg Roach
91*7dcc0dd1SGreg Roach        I18N::init('sv');
92*7dcc0dd1SGreg Roach        $request  = self::createRequest(RequestMethodInterface::METHOD_GET, [], [], [], ['tree' => $this->tree]);
93*7dcc0dd1SGreg Roach        $response = $this->module->handle($request);
94*7dcc0dd1SGreg Roach        $html     = $response->getBody()->getContents();
95*7dcc0dd1SGreg Roach        preg_match_all('/%2Findividual-list&amp;alpha=([^"&]+)/', $html, $matches);
96*7dcc0dd1SGreg Roach        self::assertEquals(['A', 'C', 'D', 'Å', 'Æ'], array_map(rawurldecode(...), $matches[1]));
97b9fc687eSGreg Roach
98*7dcc0dd1SGreg Roach        I18N::init('hu');
99*7dcc0dd1SGreg Roach        $request  = self::createRequest(RequestMethodInterface::METHOD_GET, [], [], [], ['tree' => $this->tree]);
100*7dcc0dd1SGreg Roach        $response = $this->module->handle($request);
101*7dcc0dd1SGreg Roach        $html     = $response->getBody()->getContents();
102*7dcc0dd1SGreg Roach        preg_match_all('/%2Findividual-list&amp;alpha=([^"&]+)/', $html, $matches);
103*7dcc0dd1SGreg Roach        self::assertEquals(['A', 'C', 'CS', 'DZ', 'Æ'], array_map(rawurldecode(...), $matches[1]));
104*7dcc0dd1SGreg Roach    }
105a67cd39fSGreg Roach
106*7dcc0dd1SGreg Roach    /**
107*7dcc0dd1SGreg Roach     * @covers \Fisharebest\Webtrees\Module\IndividualListModule
108*7dcc0dd1SGreg Roach     */
109*7dcc0dd1SGreg Roach    public function testRedirectToCanonicalSurname(): void
110*7dcc0dd1SGreg Roach    {
111*7dcc0dd1SGreg Roach        I18N::init('en-US');
112*7dcc0dd1SGreg Roach        $request  = self::createRequest(RequestMethodInterface::METHOD_GET, ['surname' => 'MÜLLER'], [], [], ['tree' => $this->tree]);
113*7dcc0dd1SGreg Roach        $response = $this->module->handle($request);
114*7dcc0dd1SGreg Roach        self::assertSame(StatusCodeInterface::STATUS_MOVED_PERMANENTLY, $response->getStatusCode());
115*7dcc0dd1SGreg Roach        self::assertStringContainsString('surname=MULLER', $response->getHeaderLine('Location'));
116b9fc687eSGreg Roach
117*7dcc0dd1SGreg Roach        I18N::init('de');
118*7dcc0dd1SGreg Roach        $request  = self::createRequest(RequestMethodInterface::METHOD_GET, ['surname' => 'MÜLLER'], [], [], ['tree' => $this->tree]);
119*7dcc0dd1SGreg Roach        $response = $this->module->handle($request);
120*7dcc0dd1SGreg Roach        self::assertSame(StatusCodeInterface::STATUS_MOVED_PERMANENTLY, $response->getStatusCode());
121*7dcc0dd1SGreg Roach        self::assertStringContainsString('surname=MUELLER', $response->getHeaderLine('Location'));
122*7dcc0dd1SGreg Roach    }
123*7dcc0dd1SGreg Roach
124*7dcc0dd1SGreg Roach    /**
125*7dcc0dd1SGreg Roach     * @covers \Fisharebest\Webtrees\Module\IndividualListModule
126*7dcc0dd1SGreg Roach     */
127*7dcc0dd1SGreg Roach    public function testCollationOfSurnames(): void
128*7dcc0dd1SGreg Roach    {
129*7dcc0dd1SGreg Roach        $i1 = $this->tree->createIndividual("0 @@ INDI\n1 NAME /Muller/");
130*7dcc0dd1SGreg Roach        $i2 = $this->tree->createIndividual("0 @@ INDI\n1 NAME /Müller/");
131*7dcc0dd1SGreg Roach        $i3 = $this->tree->createIndividual("0 @@ INDI\n1 NAME /Mueller/");
132*7dcc0dd1SGreg Roach
133*7dcc0dd1SGreg Roach        I18N::init('en-US');
134*7dcc0dd1SGreg Roach        $request  = self::createRequest(RequestMethodInterface::METHOD_GET, ['surname' => 'MULLER'], [], [], ['tree' => $this->tree]);
135*7dcc0dd1SGreg Roach        $response = $this->module->handle($request);
136*7dcc0dd1SGreg Roach        $html     = $response->getBody()->getContents();
137*7dcc0dd1SGreg Roach        preg_match_all('/%2Fname%2Findividual%2F(X\d+)%2F/', $html, $matches);
138*7dcc0dd1SGreg Roach        self::assertEqualsCanonicalizing([$i1->xref(), $i2->xref()], $matches[1], 'English, so U should match U and Ü');
139*7dcc0dd1SGreg Roach
140*7dcc0dd1SGreg Roach        I18N::init('de');
141*7dcc0dd1SGreg Roach        $request  = self::createRequest(RequestMethodInterface::METHOD_GET, ['surname' => 'MULLER'], [], [], ['tree' => $this->tree]);
142*7dcc0dd1SGreg Roach        $response = $this->module->handle($request);
143*7dcc0dd1SGreg Roach        $html     = $response->getBody()->getContents();
144*7dcc0dd1SGreg Roach        preg_match_all('/%2Fname%2Findividual%2F(X\d+)%2F/', $html, $matches);
145*7dcc0dd1SGreg Roach        self::assertEqualsCanonicalizing([$i1->xref()], $matches[1], 'German, so U should only match U');
146*7dcc0dd1SGreg Roach
147*7dcc0dd1SGreg Roach        $request  = self::createRequest(RequestMethodInterface::METHOD_GET, ['surname' => 'MUELLER'], [], [], ['tree' => $this->tree]);
148*7dcc0dd1SGreg Roach        $response = $this->module->handle($request);
149*7dcc0dd1SGreg Roach        $html     = $response->getBody()->getContents();
150*7dcc0dd1SGreg Roach        preg_match_all('/%2Fname%2Findividual%2F(X\d+)%2F/', $html, $matches);
151*7dcc0dd1SGreg Roach        self::assertEqualsCanonicalizing([$i2->xref(), $i3->xref()], $matches[1], 'German, so UE should also match Ü');
152*7dcc0dd1SGreg Roach    }
153*7dcc0dd1SGreg Roach
154*7dcc0dd1SGreg Roach    /**
155*7dcc0dd1SGreg Roach     * @covers \Fisharebest\Webtrees\Module\IndividualListModule
156*7dcc0dd1SGreg Roach     */
157*7dcc0dd1SGreg Roach    public function testUnknownVersusMissingSurname(): void
158*7dcc0dd1SGreg Roach    {
159*7dcc0dd1SGreg Roach        $i1 = $this->tree->createIndividual("0 @@ INDI\n1 NAME John //");
160*7dcc0dd1SGreg Roach        $i2 = $this->tree->createIndividual("0 @@ INDI\n1 NAME John");
161*7dcc0dd1SGreg Roach
162*7dcc0dd1SGreg Roach        $request  = self::createRequest(RequestMethodInterface::METHOD_GET, ['alpha' => '@'], [], [], ['tree' => $this->tree]);
163*7dcc0dd1SGreg Roach        $response = $this->module->handle($request);
164*7dcc0dd1SGreg Roach        $html     = $response->getBody()->getContents();
165*7dcc0dd1SGreg Roach        preg_match_all('/%2Fname%2Findividual%2F(X\d+)%2F/', $html, $matches);
166*7dcc0dd1SGreg Roach        self::assertEqualsCanonicalizing([$i1->xref()], $matches[1]);
167*7dcc0dd1SGreg Roach
168*7dcc0dd1SGreg Roach        $request  = self::createRequest(RequestMethodInterface::METHOD_GET, ['alpha' => ','], [], [], ['tree' => $this->tree]);
169*7dcc0dd1SGreg Roach        $response = $this->module->handle($request);
170*7dcc0dd1SGreg Roach        $html     = $response->getBody()->getContents();
171*7dcc0dd1SGreg Roach        preg_match_all('/%2Fname%2Findividual%2F(X\d+)%2F/', $html, $matches);
172*7dcc0dd1SGreg Roach        self::assertEqualsCanonicalizing([$i2->xref()], $matches[1]);
173*7dcc0dd1SGreg Roach    }
174*7dcc0dd1SGreg Roach
175*7dcc0dd1SGreg Roach    /**
176*7dcc0dd1SGreg Roach     * @covers \Fisharebest\Webtrees\Module\IndividualListModule
177*7dcc0dd1SGreg Roach     */
178*7dcc0dd1SGreg Roach    public function testAllSurnamesExcludesUnknownAndMissing(): void
179*7dcc0dd1SGreg Roach    {
180*7dcc0dd1SGreg Roach        $i1 = $this->tree->createIndividual("0 @@ INDI\n1 NAME John /Black/");
181*7dcc0dd1SGreg Roach        $i2 = $this->tree->createIndividual("0 @@ INDI\n1 NAME Mary /White/");
182*7dcc0dd1SGreg Roach        $this->tree->createIndividual("0 @@ INDI\n1 NAME Peter //");
183*7dcc0dd1SGreg Roach        $this->tree->createIndividual("0 @@ INDI\n1 NAME Paul");
184*7dcc0dd1SGreg Roach
185*7dcc0dd1SGreg Roach        $request  = self::createRequest(RequestMethodInterface::METHOD_GET, ['show_all' => 'yes'], [], [], ['tree' => $this->tree]);
186*7dcc0dd1SGreg Roach        $response = $this->module->handle($request);
187*7dcc0dd1SGreg Roach        $html     = $response->getBody()->getContents();
188*7dcc0dd1SGreg Roach        preg_match_all('/individual-list&amp;surname=([A-Z]+)/', $html, $matches);
189*7dcc0dd1SGreg Roach        self::assertEqualsCanonicalizing(['BLACK', 'WHITE'], $matches[1]);
190*7dcc0dd1SGreg Roach
191*7dcc0dd1SGreg Roach        $request  = self::createRequest(RequestMethodInterface::METHOD_GET, ['show_all' => 'yes', 'show' => 'indi'], [], [], ['tree' => $this->tree]);
192*7dcc0dd1SGreg Roach        $response = $this->module->handle($request);
193*7dcc0dd1SGreg Roach        $html     = $response->getBody()->getContents();
194*7dcc0dd1SGreg Roach        preg_match_all('/%2Fname%2Findividual%2F(X\d+)%2F/', $html, $matches);
195*7dcc0dd1SGreg Roach        self::assertEqualsCanonicalizing([$i1->xref(), $i2->xref()], $matches[1]);
196*7dcc0dd1SGreg Roach    }
197*7dcc0dd1SGreg Roach
198*7dcc0dd1SGreg Roach    /**
199*7dcc0dd1SGreg Roach     * @covers \Fisharebest\Webtrees\Module\IndividualListModule
200*7dcc0dd1SGreg Roach     */
201*7dcc0dd1SGreg Roach    public function testSurnameInitial(): void
202*7dcc0dd1SGreg Roach    {
203*7dcc0dd1SGreg Roach        $i1 = $this->tree->createIndividual("0 @@ INDI\n1 NAME John /Black/");
204*7dcc0dd1SGreg Roach        $i2 = $this->tree->createIndividual("0 @@ INDI\n1 NAME Mary /Brown/");
205*7dcc0dd1SGreg Roach        $this->tree->createIndividual("0 @@ INDI\n1 NAME Peter /White/");
206*7dcc0dd1SGreg Roach        $this->tree->createIndividual("0 @@ INDI\n1 NAME Paul /Green/");
207*7dcc0dd1SGreg Roach
208*7dcc0dd1SGreg Roach        $request  = self::createRequest(RequestMethodInterface::METHOD_GET, ['alpha' => 'B'], [], [], ['tree' => $this->tree]);
209*7dcc0dd1SGreg Roach        $response = $this->module->handle($request);
210*7dcc0dd1SGreg Roach        $html     = $response->getBody()->getContents();
211*7dcc0dd1SGreg Roach        preg_match_all('/individual-list&amp;surname=([A-Z]+)/', $html, $matches);
212*7dcc0dd1SGreg Roach        self::assertEqualsCanonicalizing(['BLACK', 'BROWN'], $matches[1]);
213*7dcc0dd1SGreg Roach
214*7dcc0dd1SGreg Roach        $request  = self::createRequest(RequestMethodInterface::METHOD_GET, ['alpha' => 'B', 'show' => 'indi'], [], [], ['tree' => $this->tree]);
215*7dcc0dd1SGreg Roach        $response = $this->module->handle($request);
216*7dcc0dd1SGreg Roach        $html     = $response->getBody()->getContents();
217*7dcc0dd1SGreg Roach        preg_match_all('/%2Fname%2Findividual%2F(X\d+)%2F/', $html, $matches);
218*7dcc0dd1SGreg Roach        self::assertEqualsCanonicalizing([$i1->xref(), $i2->xref()], $matches[1]);
219e9e85398SGreg Roach    }
220e9e85398SGreg Roach}
221